diff --git a/.github/actions/run-alpine-tests/action.yml b/.github/actions/run-alpine-tests/action.yml index 67a7cf9767..a9842c11be 100644 --- a/.github/actions/run-alpine-tests/action.yml +++ b/.github/actions/run-alpine-tests/action.yml @@ -43,7 +43,7 @@ runs: printf '%s\n' "$ALPINE_TEST_COMMAND" >> "$script_path" chmod +x "$script_path" - docker run --rm \ + docker run --rm --init \ --platform linux/amd64 \ --volume "$GITHUB_WORKSPACE:/workspace" \ --volume "$script_path:/tmp/copilot-sdk-alpine-test.sh:ro" \ diff --git a/.github/workflows/block-remove-before-merge.yml b/.github/workflows/block-remove-before-merge.yml index 443eea9f7c..0cd4a9824e 100644 --- a/.github/workflows/block-remove-before-merge.yml +++ b/.github/workflows/block-remove-before-merge.yml @@ -17,7 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: fetch-depth: 2 - name: Check for remove-before-merge paths in PR diff --git a/.github/workflows/java-publish-snapshot.yml b/.github/workflows/java-publish-snapshot.yml index ce5b8c5f4e..219dd43bf2 100644 --- a/.github/workflows/java-publish-snapshot.yml +++ b/.github/workflows/java-publish-snapshot.yml @@ -171,6 +171,80 @@ jobs: if-no-files-found: error retention-days: 1 + build-linuxmusl-arm64-classifier: + name: Build Linux musl ARM64 snapshot classifier + needs: resolve-source + runs-on: ubuntu-24.04-arm + permissions: + contents: read + outputs: + version: ${{ steps.build.outputs.version }} + defaults: + run: + shell: bash + working-directory: ./java + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + with: + node-version: 22 + + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + java-version: "25" + distribution: "microsoft" + cache: "maven" + + - name: Build and validate linuxmusl-arm64 classifier + id: build + run: | + set -euo pipefail + SOURCE_COMMIT=$(git rev-parse HEAD) + if [ "$SOURCE_COMMIT" != "${{ needs.resolve-source.outputs.source_sha }}" ]; then + echo "::error::Checked out $SOURCE_COMMIT instead of the resolved snapshot source." + exit 1 + fi + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + docker run --rm \ + --volume "$GITHUB_WORKSPACE:/workspace" \ + --volume "$HOME/.m2:/root/.m2" \ + --workdir /workspace/java \ + --env HOST_GID="$(id -g)" \ + --env HOST_UID="$(id -u)" \ + "eclipse-temurin:25-jdk-alpine" \ + sh -c "apk add --no-cache git java-cacerts maven nodejs npm && + export JAVA_TOOL_OPTIONS=-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts && + git config --global --add safe.directory /workspace && + node copilot-native/scripts/validate-native-host.mjs linuxmusl-arm64 && + mvn -B -pl copilot-native package -DskipTests -Dcopilot.native.libc=musl && + chown -R \$HOST_UID:\$HOST_GID copilot-native/target" + JAR="copilot-native/target/copilot-sdk-java-runtime-$VERSION-linuxmusl-arm64.jar" + PRIMARY_JAR="copilot-native/target/copilot-sdk-java-runtime-$VERSION.jar" + test -f "$JAR" + node copilot-native/scripts/validate-native-artifact.mjs \ + classifier linuxmusl-arm64 "$JAR" "$(basename "$JAR")" .. + node copilot-native/scripts/validate-native-artifact.mjs placeholder "$PRIMARY_JAR" + MANIFEST="copilot-native/target/linuxmusl-arm64-$VERSION.sha256" + HASH=$(sha256sum "$JAR" | cut -d ' ' -f 1) + printf '%s %s' "$HASH" "$(basename "$JAR")" > "$MANIFEST" + node copilot-native/scripts/validate-native-artifact.mjs \ + checksum "$JAR" "$MANIFEST" "$(basename "$JAR")" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: java-native-linuxmusl-arm64-snapshot-${{ github.run_id }}-${{ github.run_attempt }} + path: | + java/copilot-native/target/copilot-sdk-java-runtime-${{ steps.build.outputs.version }}-linuxmusl-arm64.jar + java/copilot-native/target/linuxmusl-arm64-${{ steps.build.outputs.version }}.sha256 + if-no-files-found: error + retention-days: 1 + build-windows-x64-classifier: name: Build Windows x64 snapshot classifier needs: resolve-source @@ -296,7 +370,7 @@ jobs: build-darwin-classifier: name: Build Darwin snapshot classifier needs: resolve-source - runs-on: macos-26 + runs-on: macos-26-agent-runtime permissions: contents: read outputs: @@ -426,6 +500,7 @@ jobs: resolve-source, build-linux-arm64-classifier, build-linuxmusl-x64-classifier, + build-linuxmusl-arm64-classifier, build-windows-x64-classifier, build-windows-arm64-classifier, build-darwin-classifier, @@ -468,6 +543,11 @@ jobs: name: java-native-linuxmusl-x64-snapshot-${{ github.run_id }}-${{ github.run_attempt }} path: ${{ runner.temp }}/java-native-linuxmusl-x64 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: java-native-linuxmusl-arm64-snapshot-${{ github.run_id }}-${{ github.run_attempt }} + path: ${{ runner.temp }}/java-native-linuxmusl-arm64 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: java-native-win32-x64-snapshot-${{ github.run_id }}-${{ github.run_attempt }} @@ -569,6 +649,31 @@ jobs: echo "linuxmusl_x64_jar=$JAR" >> "$GITHUB_OUTPUT" echo "linuxmusl_x64_sha=$(cut -d ' ' -f 1 "$MANIFEST")" >> "$GITHUB_OUTPUT" + - name: Verify version, source, and Linux musl ARM64 classifier + id: linuxmusl-arm64-artifact + run: | + SOURCE_COMMIT=$(git rev-parse HEAD) + if [ "$SOURCE_COMMIT" != "${{ needs.resolve-source.outputs.source_sha }}" ]; then + echo "::error::Checked out $SOURCE_COMMIT instead of the resolved snapshot source." + exit 1 + fi + VERSION="${{ steps.linux-arm64-artifact.outputs.version }}" + if [ "$VERSION" != "${{ needs.build-linuxmusl-arm64-classifier.outputs.version }}" ]; then + echo "::error::Linux musl ARM64 classifier version does not match deploy version." + exit 1 + fi + ARTIFACT_DIRECTORY="${{ runner.temp }}/java-native-linuxmusl-arm64" + JAR="$ARTIFACT_DIRECTORY/copilot-sdk-java-runtime-$VERSION-linuxmusl-arm64.jar" + MANIFEST="$ARTIFACT_DIRECTORY/linuxmusl-arm64-$VERSION.sha256" + test -f "$JAR" + test -f "$MANIFEST" + node "$GITHUB_WORKSPACE/java/copilot-native/scripts/validate-native-artifact.mjs" \ + checksum "$JAR" "$MANIFEST" "$(basename "$JAR")" + node "$GITHUB_WORKSPACE/java/copilot-native/scripts/validate-native-artifact.mjs" \ + classifier linuxmusl-arm64 "$JAR" "$(basename "$JAR")" "$GITHUB_WORKSPACE" + echo "linuxmusl_arm64_jar=$JAR" >> "$GITHUB_OUTPUT" + echo "linuxmusl_arm64_sha=$(cut -d ' ' -f 1 "$MANIFEST")" >> "$GITHUB_OUTPUT" + - name: Verify version, source, and Darwin classifier id: darwin-artifact run: | @@ -650,6 +755,7 @@ jobs: mvn -B deploy -DskipTests -DskipITs -Dcopilot.native.libc=glibc \ "-Dcopilot.native.external.linux.arm64.classifier.path=${{ steps.linux-arm64-artifact.outputs.linux_arm64_jar }}" \ "-Dcopilot.native.external.linuxmusl.x64.classifier.path=${{ steps.linuxmusl-x64-artifact.outputs.linuxmusl_x64_jar }}" \ + "-Dcopilot.native.external.linuxmusl.arm64.classifier.path=${{ steps.linuxmusl-arm64-artifact.outputs.linuxmusl_arm64_jar }}" \ "-Dcopilot.native.external.win32.classifier.path=${{ steps.windows-artifact.outputs.windows_jar }}" \ "-Dcopilot.native.external.win32.arm64.classifier.path=${{ steps.windows-arm64-artifact.outputs.windows_arm64_jar }}" \ "-Dcopilot.native.external.darwin.classifier.path=${{ steps.darwin-artifact.outputs.darwin_jar }}" \ @@ -689,6 +795,7 @@ jobs: echo "| \`linux-x64\` | \`ubuntu-latest\` | \`$(basename "$LINUX_JAR")\` | \`$LINUX_SHA\` | Published |" echo "| \`linux-arm64\` | \`ubuntu-24.04-arm\` | \`$(basename "${{ steps.linux-arm64-artifact.outputs.linux_arm64_jar }}")\` | \`${{ steps.linux-arm64-artifact.outputs.linux_arm64_sha }}\` | Published |" echo "| \`linuxmusl-x64\` | \`Alpine x64\` | \`$(basename "${{ steps.linuxmusl-x64-artifact.outputs.linuxmusl_x64_jar }}")\` | \`${{ steps.linuxmusl-x64-artifact.outputs.linuxmusl_x64_sha }}\` | Published |" + echo "| \`linuxmusl-arm64\` | \`Alpine ARM64\` | \`$(basename "${{ steps.linuxmusl-arm64-artifact.outputs.linuxmusl_arm64_jar }}")\` | \`${{ steps.linuxmusl-arm64-artifact.outputs.linuxmusl_arm64_sha }}\` | Published |" echo "| \`win32-x64\` | \`windows-latest\` | \`$(basename "${{ steps.windows-artifact.outputs.windows_jar }}")\` | \`${{ steps.windows-artifact.outputs.windows_sha }}\` | Published |" echo "| \`win32-arm64\` | \`windows-11-arm\` | \`$(basename "${{ steps.windows-arm64-artifact.outputs.windows_arm64_jar }}")\` | \`${{ steps.windows-arm64-artifact.outputs.windows_arm64_sha }}\` | Published |" echo "| \`darwin-x64\` | \`macos-15-intel\` | \`$(basename "${{ steps.darwin-x64-artifact.outputs.darwin_x64_jar }}")\` | \`${{ steps.darwin-x64-artifact.outputs.darwin_x64_sha }}\` | Published |" diff --git a/.github/workflows/java-smoke-test.yml b/.github/workflows/java-smoke-test.yml deleted file mode 100644 index 95f662beb1..0000000000 --- a/.github/workflows/java-smoke-test.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: "Java smoke test" - -on: - workflow_dispatch: - workflow_call: - secrets: - COPILOT_GITHUB_TOKEN: - required: true - -permissions: - contents: read - -jobs: - smoke-test-jdk17: - name: Build SDK and run smoke test (JDK 17) - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' - defaults: - run: - shell: bash - working-directory: ./java - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Set up JDK 17 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 - with: - java-version: "17" - distribution: "microsoft" - cache: "maven" - - - uses: ./.github/actions/setup-copilot - id: setup-copilot - - - name: Build SDK and install to local repo - run: mvn -DskipTests -DskipITs -Pskip-test-harness clean install - - - name: Create and run smoke test via Copilot CLI - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_CLI_JS: ${{ steps.setup-copilot.outputs.javascript-cli-path }} - run: | - cat > /tmp/smoke-test-prompt.txt << 'PROMPT_EOF' - You are running inside the copilot-sdk monorepo, in the java/ subdirectory. - The SDK has already been built and installed into the local Maven repository. - JDK 17 and Maven are already installed and on PATH. - - Execute the prompt at `sdk/src/test/prompts/PROMPT-smoke-test.md` with the following critical overrides: - - **Critical override — disable SNAPSHOT updates (but allow downloads):** The goal of this workflow is to validate the SDK SNAPSHOT that was just built and installed locally, not any newer SNAPSHOT that might exist in a remote repository. To ensure Maven does not download a newer timestamped SNAPSHOT of the SDK while still allowing it to download any missing plugins or dependencies, you must run the smoke-test Maven build without `-U` and with `--no-snapshot-updates`, so that it uses the locally installed SDK artifact. Use `mvn --no-snapshot-updates clean package` instead of `mvn -U clean package` or `mvn -o clean package`. - - **Critical override — do NOT run the jar:** Stop after the `mvn --no-snapshot-updates clean package` build succeeds. Do NOT execute Step 4 (java -jar) or Step 5 (verify exit code) from the prompt. The workflow will run the jar in a separate deterministic step to guarantee the exit code propagates correctly. - - Follow steps 1-3 only: create the `smoke-test/` directory, create `pom.xml` and the Java source file exactly as specified, and build with `mvn --no-snapshot-updates clean package` (no SNAPSHOT updates and without `-U`). - - If any step fails, exit with a non-zero exit code. Do not silently fix errors. - PROMPT_EOF - - node "$COPILOT_CLI_JS" --yolo --prompt "$(cat /tmp/smoke-test-prompt.txt)" - - - name: Run smoke test jar - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - run: | - cd smoke-test - java -jar ./target/copilot-sdk-smoketest-1.0-SNAPSHOT.jar - echo "Smoke test passed (exit code 0)" - - smoke-test-java25: - name: Build SDK and run smoke test (JDK 25) - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' - defaults: - run: - shell: bash - working-directory: ./java - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Set up JDK 25 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 - with: - java-version: "25" - distribution: "microsoft" - cache: "maven" - - - uses: ./.github/actions/setup-copilot - id: setup-copilot - - - name: Build SDK and install to local repo - run: mvn -DskipTests -DskipITs -Pskip-test-harness clean install - - - name: Create and run smoke test via Copilot CLI - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_CLI_JS: ${{ steps.setup-copilot.outputs.javascript-cli-path }} - run: | - cat > /tmp/smoke-test-prompt.txt << 'PROMPT_EOF' - You are running inside the copilot-sdk monorepo, in the java/ subdirectory. - The SDK has already been built and installed into the local Maven repository. - JDK 25 and Maven are already installed and on PATH. - - Execute the prompt at `sdk/src/test/prompts/PROMPT-smoke-test.md` with the following critical overrides: - - **Critical override — disable SNAPSHOT updates (but allow downloads):** The goal of this workflow is to validate the SDK SNAPSHOT that was just built and installed locally, not any newer SNAPSHOT that might exist in a remote repository. To ensure Maven does not download a newer timestamped SNAPSHOT of the SDK while still allowing it to download any missing plugins or dependencies, you must run the smoke-test Maven build without `-U` and with `--no-snapshot-updates`, so that it uses the locally installed SDK artifact. Use `mvn --no-snapshot-updates clean package` instead of `mvn -U clean package` or `mvn -o clean package`. - - **Critical override — do NOT run the jar:** Stop after the `mvn --no-snapshot-updates clean package` build succeeds. Do NOT execute Step 4 (java -jar) or Step 5 (verify exit code) from the prompt. The workflow will run the jar in a separate deterministic step to guarantee the exit code propagates correctly. - - **Critical override — enable Virtual Threads for JDK 25:** After creating the Java source file from the README "Quick Start" section but BEFORE building, you must modify the source file to enable virtual thread support. The Quick Start code contains inline comments that start with `// JDK 25+:` — these are instructions. Find every such comment and follow what it says (comment out lines it says to comment out, uncomment lines it says to uncomment). Add any imports required by the newly uncommented code (e.g. `java.util.concurrent.Executors`). - Also set `maven.compiler.source` and `maven.compiler.target` to `25` in the `pom.xml`. - - Follow steps 1-3 only: create the `smoke-test/` directory, create `pom.xml` and the Java source file exactly as specified, apply the JDK 25 virtual thread modifications described above, and build with `mvn --no-snapshot-updates clean package` (no SNAPSHOT updates and without `-U`). - - If any step fails, exit with a non-zero exit code. Do not silently fix errors. - PROMPT_EOF - - node "$COPILOT_CLI_JS" --yolo --prompt "$(cat /tmp/smoke-test-prompt.txt)" - - - name: Run smoke test jar - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - run: | - cd smoke-test - java -jar ./target/copilot-sdk-smoketest-1.0-SNAPSHOT.jar - echo "Smoke test passed (exit code 0)" diff --git a/.github/workflows/sdk-dotnet.yml b/.github/workflows/sdk-dotnet.yml index 4e9671c9a9..5ebbe5c0c4 100644 --- a/.github/workflows/sdk-dotnet.yml +++ b/.github/workflows/sdk-dotnet.yml @@ -1,13 +1,12 @@ # Invoked by sdk.yml to run the .NET SDK build/test matrix, documentation, # full subprocess CAPI coverage, and focused in-process smoke -# coverage on Linux and x64 musl. +# coverage across standard platforms and x64 musl. name: "SDK .NET" env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -27,7 +26,6 @@ jobs: dotnet-linux-x64: name: ".NET (ubuntu-latest, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'linux-x64' - timeout-minutes: 30 runs-on: ubuntu-latest defaults: run: @@ -38,7 +36,6 @@ jobs: DOTNET_TEST_RESULTS_DIRECTORY: TestResults/subprocess steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -83,6 +80,13 @@ jobs: DOTNET_TEST_RESULTS_DIRECTORY: TestResults/inprocess DOTNET_TEST_FILTER: "FullyQualifiedName~GitHub.Copilot.Test.E2E.ClientE2ETests.Should_Start_And_Connect_Over_InProcess_Ffi|FullyQualifiedName~GitHub.Copilot.Test.E2E.SessionE2ETests.Should_Receive_Session_Events|FullyQualifiedName~GitHub.Copilot.Test.E2E.ClientOptionsE2ETests.Should_Use_Configured_GitHub_Host_For_Authentication" run: ../scripts/ci/run-dotnet-tests.sh + - name: Validate documentation examples + if: github.event_name != 'merge_group' + working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation + run: | + npm ci + npm run extract + npm run validate:cs - if: failure() uses: actions/upload-artifact@v7 with: @@ -92,19 +96,18 @@ jobs: retention-days: 7 dotnet-darwin-arm64: - name: ".NET (macos-latest, default, CAPI)" + name: ".NET (macos-26-xlarge-agent-runtime, default, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'darwin-arm64' - runs-on: macos-latest - timeout-minutes: 30 + runs-on: macos-26-xlarge-agent-runtime defaults: run: shell: bash working-directory: ${{ inputs.sdk-home }}/dotnet env: COPILOT_SDK_E2E_BACKEND: capi + DOTNET_TEST_RESULTS_DIRECTORY: TestResults/subprocess steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -123,22 +126,41 @@ jobs: - run: dotnet build --no-restore -p:CopilotCliBinaryPath="$COPILOT_RUNTIME_BINARY_PATH" -p:CopilotSkipCliDownload=true - run: npm ci --ignore-scripts working-directory: ${{ inputs.sdk-home }}/test/harness - - env: + - name: Test out-of-process + id: subprocess + env: + COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} + run: ../scripts/ci/run-dotnet-tests.sh + - name: Test in-process smoke + if: ${{ !cancelled() && (steps.subprocess.outcome == 'success' || steps.subprocess.outcome == 'failure') }} + env: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} + COPILOT_SDK_DEFAULT_CONNECTION: inprocess + DOTNET_TEST_RESULTS_DIRECTORY: TestResults/inprocess + DOTNET_TEST_FILTER: "FullyQualifiedName~GitHub.Copilot.Test.E2E.ClientE2ETests.Should_Start_And_Connect_Over_InProcess_Ffi|FullyQualifiedName~GitHub.Copilot.Test.E2E.SessionE2ETests.Should_Receive_Session_Events|FullyQualifiedName~GitHub.Copilot.Test.E2E.ClientOptionsE2ETests.Should_Use_Configured_GitHub_Host_For_Authentication" run: ../scripts/ci/run-dotnet-tests.sh - if: failure() uses: actions/upload-artifact@v7 with: - name: dotnet-test-diagnostics-macos-latest-default-capi-${{ github.run_attempt }} + name: dotnet-test-diagnostics-macos-26-xlarge-default-capi-${{ github.run_attempt }} path: ${{ inputs.sdk-home }}/dotnet/TestResults/ if-no-files-found: warn retention-days: 7 dotnet-win32-x64: - name: ".NET (windows-latest, default, CAPI)" + name: ".NET (windows-latest, ${{ matrix.framework }}, ${{ matrix.suite.name }}, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'win32-x64' runs-on: windows-latest - timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + framework: [net8.0, net472] + # Complementary filters include every test, including newly added classes. + suite: + - name: e2e-s + filter: FullyQualifiedName~GitHub.Copilot.Test.E2E.S + - name: remaining + filter: FullyQualifiedName!~GitHub.Copilot.Test.E2E.S defaults: run: shell: bash @@ -146,9 +168,11 @@ jobs: env: COPILOT_SDK_E2E_BACKEND: capi DOTNET_TEST_RUNTIME: win-x64 + DOTNET_TEST_FRAMEWORK: ${{ matrix.framework }} + DOTNET_TEST_FILTER: ${{ matrix.suite.filter }} + DOTNET_TEST_RESULTS_DIRECTORY: TestResults/subprocess steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -164,17 +188,27 @@ jobs: with: node-version: 22 - run: dotnet restore test/GitHub.Copilot.SDK.Test.csproj --runtime "$DOTNET_TEST_RUNTIME" -p:CopilotCliBinaryPath="$COPILOT_RUNTIME_BINARY_PATH" -p:CopilotSkipCliDownload=true - - run: dotnet build test/GitHub.Copilot.SDK.Test.csproj --no-restore --runtime "$DOTNET_TEST_RUNTIME" -p:CopilotCliBinaryPath="$COPILOT_RUNTIME_BINARY_PATH" -p:CopilotSkipCliDownload=true + - run: dotnet build test/GitHub.Copilot.SDK.Test.csproj --no-restore --framework "$DOTNET_TEST_FRAMEWORK" --runtime "$DOTNET_TEST_RUNTIME" -p:CopilotCliBinaryPath="$COPILOT_RUNTIME_BINARY_PATH" -p:CopilotSkipCliDownload=true - run: npm ci --ignore-scripts working-directory: ${{ inputs.sdk-home }}/test/harness - run: pwsh.exe -Command "Write-Host 'PowerShell ready'" - - env: + - name: Test out-of-process + id: subprocess + env: + COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} + run: ../scripts/ci/run-dotnet-tests.sh + - name: Test in-process smoke + if: ${{ !cancelled() && (steps.subprocess.outcome == 'success' || steps.subprocess.outcome == 'failure') }} + env: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} + COPILOT_SDK_DEFAULT_CONNECTION: inprocess + DOTNET_TEST_RESULTS_DIRECTORY: TestResults/inprocess + DOTNET_TEST_FILTER: "FullyQualifiedName~GitHub.Copilot.Test.E2E.ClientE2ETests.Should_Start_And_Connect_Over_InProcess_Ffi|FullyQualifiedName~GitHub.Copilot.Test.E2E.SessionE2ETests.Should_Receive_Session_Events|FullyQualifiedName~GitHub.Copilot.Test.E2E.ClientOptionsE2ETests.Should_Use_Configured_GitHub_Host_For_Authentication" run: ../scripts/ci/run-dotnet-tests.sh - if: failure() uses: actions/upload-artifact@v7 with: - name: dotnet-test-diagnostics-windows-latest-default-capi-${{ github.run_attempt }} + name: dotnet-test-diagnostics-windows-latest-${{ matrix.framework }}-${{ matrix.suite.name }}-capi-${{ github.run_attempt }} path: ${{ inputs.sdk-home }}/dotnet/TestResults/ if-no-files-found: warn retention-days: 7 @@ -183,12 +217,10 @@ jobs: name: ".NET (Alpine x64, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 20 env: COPILOT_SDK_E2E_BACKEND: capi steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -257,25 +289,3 @@ jobs: path: ${{ inputs.sdk-home }}/dotnet/TestResults/ if-no-files-found: warn retention-days: 7 - - docs-dotnet: - name: "Docs (.NET)" - if: inputs.platform == 'all' || inputs.platform == 'docs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - timeout-minutes: 4 - with: - persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version: 22 - - uses: actions/setup-dotnet@v6 - with: - dotnet-version: "10.0.x" - - run: npm ci - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation - - run: dotnet restore -p:CopilotSkipCliDownload=true - working-directory: ${{ inputs.sdk-home }}/dotnet - - run: npm run extract && npm run validate:cs - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation diff --git a/.github/workflows/sdk-go.yml b/.github/workflows/sdk-go.yml index 24ef16a35b..d07042076e 100644 --- a/.github/workflows/sdk-go.yml +++ b/.github/workflows/sdk-go.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -30,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-latest"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-latest","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} defaults: run: @@ -38,7 +37,6 @@ jobs: working-directory: ${{ inputs.sdk-home }}/go steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -68,7 +66,9 @@ jobs: - if: runner.os == 'Linux' run: go test ./... working-directory: ${{ inputs.sdk-home }}/go/samples - - run: npm ci --ignore-scripts + - run: | + npm ci --ignore-scripts + npm rebuild esbuild working-directory: ${{ inputs.sdk-home }}/test/harness - if: runner.os == 'Windows' run: pwsh.exe -Command "Write-Host 'PowerShell ready'" @@ -86,15 +86,24 @@ jobs: run: | go test -v -race -timeout=20m ./internal/e2e -run '^TestInProcessFfiE2E$' go test -v -race -timeout=20m ./internal/e2e -run '^TestClientE2E$/^should_use_configured_github_host_for_authentication$' + - if: github.event_name != 'merge_group' && runner.os == 'Linux' + uses: actions/setup-node@v6 + with: + node-version: 22 + - name: Validate documentation examples + if: github.event_name != 'merge_group' && runner.os == 'Linux' + working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation + run: | + npm ci + npm run extract + npm run validate:go go-musl-x64: name: "Go (Alpine x64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 20 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -114,6 +123,7 @@ jobs: apk add --no-cache build-base nodejs npm npm --prefix "$COPILOT_SDK_ROOT/nodejs" ci --ignore-scripts npm --prefix "$COPILOT_SDK_ROOT/test/harness" ci --ignore-scripts + npm --prefix "$COPILOT_SDK_ROOT/test/harness" rebuild esbuild export GITHUB_ENV=/tmp/copilot-sdk-runtime.env export COPILOT_RUNTIME_TARGET=linuxmusl-x64 @@ -138,24 +148,3 @@ jobs: go test -v -race -timeout=20m ./internal/e2e -run '^TestInProcessFfiE2E$' || status=$? go test -v -race -timeout=20m ./internal/e2e -run '^TestClientE2E$/^should_use_configured_github_host_for_authentication$' || status=$? exit "$status" - - docs-go: - name: "Docs (Go)" - if: inputs.platform == 'all' || inputs.platform == 'docs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - timeout-minutes: 4 - with: - persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version: 22 - - uses: actions/setup-go@v6 - with: - go-version: "1.24" - cache-dependency-path: ${{ inputs.sdk-home }}/go/go.sum - - run: npm ci - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation - - run: npm run extract && npm run validate:go - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation diff --git a/.github/workflows/sdk-java.yml b/.github/workflows/sdk-java.yml index 408298d88c..28f9650925 100644 --- a/.github/workflows/sdk-java.yml +++ b/.github/workflows/sdk-java.yml @@ -1,12 +1,11 @@ -# Invoked by sdk.yml to run full subprocess Java SDK coverage on supported JDKs, -# focused in-process smoke coverage across native classifiers, and documentation. +# Invoked by sdk.yml to run full subprocess Java SDK coverage followed by focused +# in-process smoke on standard platforms and x64 musl, plus JDK 17 and docs checks. name: "SDK Java" env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -24,25 +23,30 @@ permissions: jobs: java: - name: "Java (JDK ${{ matrix.test-jdk }})" - if: inputs.platform == 'all' || inputs.platform == 'linux-x64' + name: "Java (${{ matrix.os }}, JDK ${{ matrix.test-jdk }})" + if: contains(fromJSON('["all","linux-x64","darwin-arm64","win32-x64"]'), inputs.platform) strategy: fail-fast: false matrix: + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} test-jdk: ["25", "17"] - runs-on: ubuntu-latest + exclude: + - os: macos-26-agent-runtime + test-jdk: "17" + - os: windows-latest + test-jdk: "17" + runs-on: ${{ matrix.os }} defaults: run: shell: bash working-directory: ${{ inputs.sdk-home }}/java steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime with: - artifact-name: executable-sdk-Linux-X64-gnu + artifact-name: ${{ runner.os == 'Linux' && format('executable-sdk-{0}-{1}-gnu', runner.os, runner.arch) || format('executable-sdk-{0}-{1}', runner.os, runner.arch) }} path: ${{ github.workspace }} - run: node "$SDK_HOME/scripts/ci/runtime-artifact.mjs" restore && node "$SDK_HOME/scripts/ci/runtime-artifact.mjs" prepare working-directory: . @@ -56,13 +60,15 @@ jobs: node-version: 22 # TEMPORARY MERGE QUEUE REDUCTION: pull requests and main pushes retain # static checks; merge groups rerun only SDK compatibility coverage. - - if: github.event_name != 'merge_group' && matrix.test-jdk == '25' + - if: github.event_name != 'merge_group' && runner.os == 'Linux' && matrix.test-jdk == '25' run: ./scripts/test-update-documentation-versions.sh - run: ./mvnw test-compile jar:jar - - if: github.event_name != 'merge_group' && matrix.test-jdk == '25' + - if: github.event_name != 'merge_group' && runner.os == 'Linux' && matrix.test-jdk == '25' run: ./mvnw javadoc:javadoc - - if: github.event_name != 'merge_group' && matrix.test-jdk == '25' + - if: github.event_name != 'merge_group' && runner.os == 'Linux' && matrix.test-jdk == '25' run: ./mvnw spotless:check + - if: runner.os == 'Windows' + run: pwsh.exe -Command "Write-Host 'PowerShell ready'" - if: matrix.test-jdk == '25' id: subprocess env: @@ -94,10 +100,19 @@ jobs: -Dsurefire.failIfNoSpecifiedTests=false \ -Dit.test=InProcessTransportIT,AuthHostE2ETest \ -Dcopilot.inprocess.cli.path="$COPILOT_CLI_PATH" + - if: github.event_name != 'merge_group' && runner.os == 'Linux' && matrix.test-jdk == '25' + run: ./mvnw install -Dmaven.test.skip=true -Dskip.test.harness=true -Dcopilot.native.skip.download=true + - name: Validate documentation examples + if: github.event_name != 'merge_group' && runner.os == 'Linux' && matrix.test-jdk == '25' + working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation + run: | + npm ci + npm run extract + npm run validate:java - if: failure() uses: actions/upload-artifact@v7 with: - name: java-test-results-jdk-${{ matrix.test-jdk }} + name: java-test-results-${{ matrix.os }}-jdk-${{ matrix.test-jdk }} path: | ${{ inputs.sdk-home }}/java/sdk/target/surefire-reports/ ${{ inputs.sdk-home }}/java/sdk/target/surefire-reports-isolated/ @@ -105,132 +120,129 @@ jobs: ${{ inputs.sdk-home }}/java/sdk/target/subprocess-reports/ retention-days: 7 - java-inprocess: - name: "Java (inprocess, ${{ matrix.classifier }})" - if: contains(fromJSON('["all","darwin-arm64","win32-x64"]'), inputs.platform) - strategy: - fail-fast: false - matrix: - include: ${{ fromJSON(inputs.platform == 'darwin-arm64' && '[{"os":"macos-26","classifier":"darwin-arm64"}]' || inputs.platform == 'win32-x64' && '[{"os":"windows-latest","classifier":"win32-x64"}]' || '[{"os":"windows-latest","classifier":"win32-x64"},{"os":"macos-26","classifier":"darwin-arm64"}]') }} - runs-on: ${{ matrix.os }} - defaults: - run: - shell: bash - working-directory: ${{ inputs.sdk-home }}/java + java-musl-x64: + name: "Java (JDK 25, linuxmusl-x64)" + if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' + runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime with: - artifact-name: ${{ runner.os == 'Linux' && format('executable-sdk-{0}-{1}-gnu', runner.os, runner.arch) || format('executable-sdk-{0}-{1}', runner.os, runner.arch) }} + artifact-name: executable-sdk-Linux-X64-musl path: ${{ github.workspace }} - - run: node "$SDK_HOME/scripts/ci/runtime-artifact.mjs" restore && node "$SDK_HOME/scripts/ci/runtime-artifact.mjs" prepare + - run: node "$SDK_HOME/scripts/ci/runtime-artifact.mjs" restore working-directory: . - - uses: actions/setup-java@v5 - with: - java-version: "25" - distribution: microsoft - cache: maven - - uses: actions/setup-node@v6 + - uses: ./.github/actions/run-alpine-tests + env: + COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} with: - node-version: 22 - - env: - CI: "true" - run: >- - ./mvnw clean verify -Pinprocess - -Dtest=NoTestsForInProcessSmoke - -Dsurefire.failIfNoSpecifiedTests=false - -Dit.test=InProcessTransportIT,AuthHostE2ETest - -Dcopilot.inprocess.cli.path="$COPILOT_CLI_PATH" + image: eclipse-temurin:25-jdk-alpine + sdk-root: /workspace/${{ inputs.sdk-home }} + workdir: /workspace/${{ inputs.sdk-home }}/java + command: | + apk add --no-cache java-cacerts maven nodejs npm + export JAVA_TOOL_OPTIONS=-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts + export GITHUB_ENV=/tmp/copilot-sdk-runtime.env + export COPILOT_RUNTIME_TARGET=linuxmusl-x64 + export COPILOT_RUNTIME_OUTPUT_DIRECTORY=/workspace/.sdk-runtime/linuxmusl-x64 + node "$COPILOT_SDK_ROOT/scripts/ci/runtime-artifact.mjs" prepare + set -a + . "$GITHUB_ENV" + set +a + node copilot-native/scripts/validate-native-host.mjs linuxmusl-x64 + ./mvnw test-compile jar:jar -Dcopilot.native.libc=musl + status=0 + ./mvnw -pl sdk verify -Dskip.test.harness=true -Dcopilot.cli.path="$COPILOT_CLI_PATH" || status=$? + mkdir -p sdk/target/subprocess-reports + for reports in surefire-reports surefire-reports-isolated failsafe-reports; do + if [ -d "sdk/target/$reports" ]; then + mv "sdk/target/$reports" sdk/target/subprocess-reports/ + fi + done + ./mvnw verify -Pinprocess \ + -Dskip.test.harness=true \ + -Dtest=NoTestsForInProcessSmoke \ + -Dsurefire.failIfNoSpecifiedTests=false \ + -Dit.test=InProcessTransportIT,AuthHostE2ETest \ + -Dcopilot.native.libc=musl \ + -Dcopilot.inprocess.cli.path="$COPILOT_CLI_PATH" || status=$? + exit "$status" - if: failure() uses: actions/upload-artifact@v7 with: - name: java-test-results-inprocess-${{ matrix.classifier }} + name: java-test-results-linuxmusl-x64 path: | ${{ inputs.sdk-home }}/java/sdk/target/surefire-reports/ ${{ inputs.sdk-home }}/java/sdk/target/surefire-reports-isolated/ ${{ inputs.sdk-home }}/java/sdk/target/failsafe-reports/ + ${{ inputs.sdk-home }}/java/sdk/target/subprocess-reports/ retention-days: 7 - - java-inprocess-musl-x64: - name: "Java (inprocess, linuxmusl-x64)" - if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' - runs-on: ubuntu-latest - timeout-minutes: 30 + java-musl-arm64: + name: "Java (JDK 25, linuxmusl-arm64)" + if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-arm64' + runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime with: - artifact-name: executable-sdk-Linux-X64-musl + artifact-name: executable-sdk-Linux-ARM64-musl path: ${{ github.workspace }} - run: node "$SDK_HOME/scripts/ci/runtime-artifact.mjs" restore working-directory: . - - name: Run Java SDK tests (InProcess, musl) + - name: Run Java SDK tests (linuxmusl-arm64) env: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} run: | - docker run --rm \ + docker run --rm --init \ --volume "$GITHUB_WORKSPACE:/workspace" \ --workdir "/workspace/$SDK_HOME/java" \ --env CI=true \ --env COPILOT_HMAC_KEY \ --env GITHUB_ACTIONS=true \ --env GITHUB_WORKSPACE=/workspace \ - --env SDK_HOME="/workspace/$SDK_HOME" \ + --env COPILOT_SDK_ROOT="/workspace/$SDK_HOME" \ eclipse-temurin:25-jdk-alpine \ sh -c 'set -eux - apk add --no-cache git java-cacerts maven nodejs npm - export JAVA_TOOL_OPTIONS=-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts + apk add --no-cache bash git java-cacerts maven nodejs npm + bash --noprofile --norc -c "exit 0" git config --global --add safe.directory /workspace + export JAVA_TOOL_OPTIONS=-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts export GITHUB_ENV=/tmp/copilot-sdk-runtime.env - export COPILOT_RUNTIME_TARGET=linuxmusl-x64 - export COPILOT_RUNTIME_OUTPUT_DIRECTORY=/workspace/.sdk-runtime/linuxmusl-x64 - node "$SDK_HOME/scripts/ci/runtime-artifact.mjs" prepare + export COPILOT_RUNTIME_TARGET=linuxmusl-arm64 + export COPILOT_RUNTIME_OUTPUT_DIRECTORY=/workspace/.sdk-runtime/linuxmusl-arm64 + node "$COPILOT_SDK_ROOT/scripts/ci/runtime-artifact.mjs" prepare set -a . "$GITHUB_ENV" set +a - node copilot-native/scripts/validate-native-host.mjs linuxmusl-x64 - ./mvnw clean verify -Pinprocess \ + node copilot-native/scripts/validate-native-host.mjs linuxmusl-arm64 + ./mvnw test-compile jar:jar -Dcopilot.native.libc=musl + status=0 + ./mvnw -pl sdk verify -Dskip.test.harness=true -Dcopilot.cli.path="$COPILOT_CLI_PATH" || status=$? + mkdir -p sdk/target/subprocess-reports + for reports in surefire-reports surefire-reports-isolated failsafe-reports; do + if [ -d "sdk/target/$reports" ]; then + mv "sdk/target/$reports" sdk/target/subprocess-reports/ + fi + done + ./mvnw verify -Pinprocess \ + -Dskip.test.harness=true \ -Dtest=NoTestsForInProcessSmoke \ -Dsurefire.failIfNoSpecifiedTests=false \ -Dit.test=InProcessTransportIT,AuthHostE2ETest \ -Dcopilot.native.libc=musl \ - -Dcopilot.inprocess.cli.path="$COPILOT_CLI_PATH"' + -Dcopilot.inprocess.cli.path="$COPILOT_CLI_PATH" || status=$? + exit "$status"' - if: failure() uses: actions/upload-artifact@v7 with: - name: java-test-results-inprocess-linuxmusl-x64 + name: java-test-results-linuxmusl-arm64 path: | ${{ inputs.sdk-home }}/java/sdk/target/surefire-reports/ ${{ inputs.sdk-home }}/java/sdk/target/surefire-reports-isolated/ ${{ inputs.sdk-home }}/java/sdk/target/failsafe-reports/ + ${{ inputs.sdk-home }}/java/sdk/target/subprocess-reports/ retention-days: 7 - - docs-java: - name: "Docs (Java)" - if: inputs.platform == 'all' || inputs.platform == 'docs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - timeout-minutes: 4 - with: - persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version: 22 - - uses: actions/setup-java@v5 - with: - distribution: microsoft - java-version: "25" - cache: maven - - run: ./mvnw install -Dmaven.test.skip=true -Dskip.test.harness=true -Dcopilot.native.skip.download=true - working-directory: ${{ inputs.sdk-home }}/java - - run: npm ci - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation - - run: npm run extract && npm run validate:java - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation diff --git a/.github/workflows/sdk-nodejs.yml b/.github/workflows/sdk-nodejs.yml index 315331609b..d573049446 100644 --- a/.github/workflows/sdk-nodejs.yml +++ b/.github/workflows/sdk-nodejs.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -19,6 +18,11 @@ on: sdk-home: required: true type: string + outputs: + capi-result: + description: "Standard-platform CAPI job result, independent of BYOK jobs" + # Direct result outputs can be empty: https://github.com/actions/runner/issues/2495 + value: ${{ fromJSON(toJSON(jobs.nodejs)).result }} permissions: contents: read @@ -30,7 +34,7 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-latest"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-latest","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} defaults: run: @@ -38,7 +42,6 @@ jobs: working-directory: ${{ inputs.sdk-home }}/nodejs steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -89,17 +92,17 @@ jobs: env: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} run: | - if [ "$GITHUB_EVENT_NAME" = "merge_group" ]; then + if [ "$GITHUB_EVENT_NAME" = "merge_group" ] || [ "$GITHUB_EVENT_NAME" = "pull_request" ] || [ "$GITHUB_EVENT_NAME" = "push" ]; then npm test -- --reporter=default --reporter=json --outputFile="$RUNNER_TEMP/sdk-nodejs-results.json" else npm test fi - - name: Upload merge-queue Node.js test results - if: always() && github.event_name == 'merge_group' && runner.os == 'Linux' + - name: Upload Flake Finder Node.js test results + if: always() && (github.event_name == 'merge_group' || github.event_name == 'pull_request' || github.event_name == 'push') continue-on-error: true uses: actions/upload-artifact@v7 with: - name: suspected-flakes-sdk-nodejs-${{ github.run_attempt }}-linux + name: suspected-flakes-sdk-nodejs-${{ github.run_attempt }}-${{ runner.os == 'macOS' && 'macos' || runner.os == 'Windows' && 'windows' || 'linux' }} path: ${{ runner.temp }}/sdk-nodejs-results.json if-no-files-found: warn retention-days: 7 @@ -109,6 +112,13 @@ jobs: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} COPILOT_SDK_DEFAULT_CONNECTION: inprocess run: npm test -- test/e2e/inprocess_ffi.e2e.test.ts test/e2e/auth_host.e2e.test.ts + - name: Validate documentation examples + if: github.event_name != 'merge_group' && runner.os == 'Linux' + working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation + run: | + npm ci + npm run extract + npm run validate:ts # Keep each BYOK backend on its own runner; shared runtime E2E coverage belongs # in TypeScript rather than repeating these sweeps across SDK languages. @@ -116,7 +126,6 @@ jobs: name: "Node.js (ubuntu-latest, ${{ matrix.backend }})" if: github.event_name != 'merge_group' && (inputs.platform == 'all' || inputs.platform == 'linux-x64') runs-on: ubuntu-latest - timeout-minutes: 30 strategy: fail-fast: false matrix: @@ -129,7 +138,6 @@ jobs: COPILOT_SDK_E2E_BACKEND: ${{ matrix.backend }} steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -158,7 +166,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -197,24 +204,3 @@ jobs: npm test || status=$? COPILOT_SDK_DEFAULT_CONNECTION=inprocess npm test -- test/e2e/inprocess_ffi.e2e.test.ts test/e2e/auth_host.e2e.test.ts || status=$? exit "$status" - - docs-typescript: - name: "Docs (TypeScript)" - if: inputs.platform == 'all' || inputs.platform == 'docs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - timeout-minutes: 4 - with: - persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version: 22 - cache: npm - cache-dependency-path: ${{ inputs.sdk-home }}/nodejs/package-lock.json - - run: npm ci --ignore-scripts - working-directory: ${{ inputs.sdk-home }}/nodejs - - run: npm ci - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation - - run: npm run extract && npm run validate:ts - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation diff --git a/.github/workflows/sdk-platform.yml b/.github/workflows/sdk-platform.yml index b21a9106fc..f1ed4e6ed4 100644 --- a/.github/workflows/sdk-platform.yml +++ b/.github/workflows/sdk-platform.yml @@ -16,6 +16,9 @@ on: description: "Node.js SDK result, independent of other languages" # Direct result outputs can be empty: https://github.com/actions/runner/issues/2495 value: ${{ fromJSON(toJSON(jobs.nodejs)).result }} + nodejs-capi-result: + description: "Standard-platform Node.js CAPI result, independent of BYOK and other languages" + value: ${{ jobs.nodejs.outputs.capi-result }} permissions: contents: read diff --git a/.github/workflows/sdk-python.yml b/.github/workflows/sdk-python.yml index 71bedf2eaa..b2db80794b 100644 --- a/.github/workflows/sdk-python.yml +++ b/.github/workflows/sdk-python.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -30,9 +29,8 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-latest"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-latest","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} - timeout-minutes: 20 defaults: run: shell: bash @@ -41,7 +39,6 @@ jobs: PYTHONUTF8: 1 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -83,6 +80,14 @@ jobs: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} COPILOT_SDK_DEFAULT_CONNECTION: inprocess run: uv run --locked pytest -v -s e2e/test_inprocess_ffi_e2e.py e2e/test_auth_host_e2e.py + - name: Validate documentation examples + if: github.event_name != 'merge_group' && runner.os == 'Linux' + working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation + run: | + npm ci + npm run extract + uv run --locked --python 3.12 --project "$GITHUB_WORKSPACE/$SDK_HOME/python" python3 -m mypy --version + uv run --locked --python 3.12 --project "$GITHUB_WORKSPACE/$SDK_HOME/python" npm run validate:py - name: Upload Python test diagnostics if: failure() uses: actions/upload-artifact@v7 @@ -97,10 +102,8 @@ jobs: name: "Python (Alpine x64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 20 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -149,29 +152,3 @@ jobs: include-hidden-files: true if-no-files-found: warn retention-days: 7 - - docs-python: - name: "Docs (Python)" - if: inputs.platform == 'all' || inputs.platform == 'docs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - timeout-minutes: 4 - with: - persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version: 22 - - uses: actions/setup-python@v6 - with: - python-version: "3.12" - - uses: astral-sh/setup-uv@v7 - - run: uv sync --locked - working-directory: ${{ inputs.sdk-home }}/python - - run: npm ci - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation - - run: npm run extract - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation - - run: uv run --locked --project "$GITHUB_WORKSPACE/$SDK_HOME/python" python3 -m mypy --version - - run: uv run --locked --project "$GITHUB_WORKSPACE/$SDK_HOME/python" npm run validate:py - working-directory: ${{ inputs.sdk-home }}/scripts/docs-validation diff --git a/.github/workflows/sdk-runtime-artifact.yml b/.github/workflows/sdk-runtime-artifact.yml index 0481e945ae..51c226b429 100644 --- a/.github/workflows/sdk-runtime-artifact.yml +++ b/.github/workflows/sdk-runtime-artifact.yml @@ -11,7 +11,6 @@ env: GIT_HTTP_LOW_SPEED_LIMIT: 1000 GIT_HTTP_LOW_SPEED_TIME: 60 HUSKY: 0 - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -47,10 +46,6 @@ on: required: false default: "" type: string - timeout-minutes: - required: false - default: 90 - type: number permissions: contents: read @@ -63,7 +58,6 @@ jobs: cache-relay: if: inputs.runtime-source == 'checkout' runs-on: ubuntu-slim - timeout-minutes: 15 permissions: actions: read contents: read @@ -71,7 +65,7 @@ jobs: cache-hit: ${{ steps.cache.outputs.cache-hit }} steps: - uses: actions/checkout@v7 - timeout-minutes: 4 + timeout-minutes: 60 with: persist-credentials: false @@ -144,7 +138,6 @@ jobs: (inputs.runtime-source == 'published' || (needs.cache-relay.result == 'success' && needs.cache-relay.outputs.cache-hit != 'true')) runs-on: ${{ inputs.runtime-source == 'checkout' && inputs.os || 'ubuntu-latest' }} - timeout-minutes: ${{ inputs.timeout-minutes }} permissions: actions: read contents: read @@ -152,7 +145,7 @@ jobs: packages: read steps: - uses: actions/checkout@v7 - timeout-minutes: 4 + timeout-minutes: 60 with: persist-credentials: false @@ -197,7 +190,7 @@ jobs: - if: inputs.runtime-source == 'checkout' && steps.cache.outputs.cache-hit != 'true' uses: ./.github/actions/setup-node - timeout-minutes: ${{ fromJSON(env.SETUP_NODE_TIMEOUT_MINUTES) }} + timeout-minutes: 60 - name: Capture verified addon source identity if: inputs.runtime-source == 'checkout' && steps.cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/sdk-rust.yml b/.github/workflows/sdk-rust.yml index 5ab3134139..902ae8ed11 100644 --- a/.github/workflows/sdk-rust.yml +++ b/.github/workflows/sdk-rust.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -27,11 +26,10 @@ jobs: rust: name: "Rust (${{ matrix.os }})" if: contains(fromJSON('["all","linux-x64","darwin-arm64","win32-x64"]'), inputs.platform) - timeout-minutes: 60 strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-latest"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-latest","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-xlarge-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-xlarge-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} defaults: run: @@ -40,9 +38,11 @@ jobs: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 + # Preserve source-line backtraces without full variable/type debug information. + CARGO_PROFILE_DEV_DEBUG: line-tables-only + CARGO_PROFILE_TEST_DEBUG: line-tables-only steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -106,7 +106,7 @@ jobs: - name: Test in-process smoke id: inprocess - if: ${{ !cancelled() && runner.os != 'Windows' && (steps.subprocess.outcome == 'success' || steps.subprocess.outcome == 'failure') }} + if: ${{ !cancelled() && (steps.subprocess.outcome == 'success' || steps.subprocess.outcome == 'failure') }} env: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} COPILOT_SDK_DEFAULT_CONNECTION: inprocess @@ -128,10 +128,8 @@ jobs: name: "Rust (Alpine x64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 60 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml index b6314e62f6..852163ec93 100644 --- a/.github/workflows/sdk.yml +++ b/.github/workflows/sdk.yml @@ -9,7 +9,6 @@ env: COPILOT_BAZEL_ANG_PR_SAMPLED_MODE: ${{ vars.COPILOT_BAZEL_ANG_PR_SAMPLED_MODE }} HUSKY: 0 POWERSHELL_UPDATECHECK: Off - SETUP_NODE_TIMEOUT_MINUTES: 10 on: pull_request: @@ -27,17 +26,163 @@ permissions: contents: read jobs: + detect-sdk-changes: + name: "Detect SDK-impacting changes" + runs-on: ubuntu-slim + outputs: + has_sdk_changes: ${{ steps.full-coverage.outputs.has_sdk_changes || steps.classify.outputs.has_sdk_changes || steps.recover.outputs.has_sdk_changes }} + steps: + - name: Require full coverage outside pull requests + id: full-coverage + if: github.event_name != 'pull_request' + run: echo "has_sdk_changes=true" >> "$GITHUB_OUTPUT" + + - uses: actions/checkout@v7 + id: checkout + if: github.event_name == 'pull_request' + continue-on-error: true + with: + # Include the synthetic merge commit's base parent without fetching + # repository history. + fetch-depth: 2 + persist-credentials: false + + - name: Detect repository layout + id: repository-layout + if: steps.checkout.outcome == 'success' + continue-on-error: true + run: | + trusted_revision="$(git rev-parse "$GITHUB_SHA^1")" + echo "base-sha=$trusted_revision" >> "$GITHUB_OUTPUT" + if git cat-file -e "${trusted_revision}:src/sdk/package.json" 2>/dev/null && + git cat-file -e "${trusted_revision}:script/sea-build.ts" 2>/dev/null; then + echo "layout=runtime" >> "$GITHUB_OUTPUT" + elif git cat-file -e "${trusted_revision}:package.json" 2>/dev/null && + git cat-file -e "${trusted_revision}:nodejs/package.json" 2>/dev/null; then + echo "layout=standalone" >> "$GITHUB_OUTPUT" + else + echo "::warning::Unable to identify the SDK repository layout; requiring full coverage." + exit 1 + fi + + - name: Find SDK-impacting paths + id: filter + if: steps.repository-layout.outcome == 'success' + continue-on-error: true + uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6 + with: + base_sha: ${{ steps.repository-layout.outputs.base-sha }} + sha: ${{ github.sha }} + skip_initial_fetch: true + fail_on_initial_diff_error: true + quotepath: false + files_yaml: | + runtime: + - .github/actions/** + - .github/workflows/sdk*.yml + - .github/workflows/sdk*.yaml + - .github/workflows/shared-cli-build.yml + - .github/workflows/publish.yml + - .editorconfig + - .gitattributes + - .nvmrc + - package.json + - package-lock.json + - pnpm-lock.yaml + - sdk-protocol-version.json + - assets/** + - BUILD.bazel + - src/** + - generated/** + - schema/** + - files/** + - third_party/** + - patches/** + - tools/bazel/** + - .cargo/** + - bazel/** + - script/** + - .bazelignore + - .bazelrc + - .bazelversion + - Cargo.lock + - Cargo.toml + - MODULE.bazel + - MODULE.bazel.lock + - pnpm-workspace.yaml + - rust-toolchain.toml + - esbuild.ts + - tsconfig*.json + standalone: + - .github/actions/** + - .github/workflows/sdk*.yml + - .github/workflows/sdk*.yaml + - .github/workflows/shared-cli-build.yml + - .github/workflows/publish.yml + - .editorconfig + - .gitattributes + - .nvmrc + - package.json + - package-lock.json + - pnpm-lock.yaml + - sdk-protocol-version.json + - assets/** + - BUILD.bazel + - nodejs/** + - python/** + - go/** + - dotnet/** + - java/** + - rust/** + - scripts/** + - samples/** + - test/** + - docs/** + - README.md + - vitest.config.ts + + - name: Select layout-specific result + id: classify + if: steps.filter.outcome == 'success' + env: + LAYOUT: ${{ steps.repository-layout.outputs.layout }} + RUNTIME_CHANGED: ${{ steps.filter.outputs.runtime_any_modified }} + STANDALONE_CHANGED: ${{ steps.filter.outputs.standalone_any_modified }} + run: | + if [[ "$LAYOUT" == "runtime" ]]; then + has_sdk_changes="$RUNTIME_CHANGED" + elif [[ "$LAYOUT" == "standalone" ]]; then + has_sdk_changes="$STANDALONE_CHANGED" + else + exit 1 + fi + echo "has_sdk_changes=$has_sdk_changes" >> "$GITHUB_OUTPUT" + + - name: Require full coverage after detection errors + id: recover + if: github.event_name == 'pull_request' && (steps.checkout.outcome != 'success' || steps.repository-layout.outcome != 'success' || steps.filter.outcome != 'success' || steps.classify.outcome != 'success') + run: | + echo "::warning::SDK change detection failed; requiring full coverage." + echo "has_sdk_changes=true" >> "$GITHUB_OUTPUT" + detect-layout: name: "Detect SDK layout" + needs: detect-sdk-changes + if: ${{ !cancelled() && (needs.detect-sdk-changes.result != 'success' || needs.detect-sdk-changes.outputs.has_sdk_changes == 'true') }} runs-on: ubuntu-latest outputs: runtime-source: ${{ steps.detect.outputs.runtime-source }} sdk-home: ${{ steps.detect.outputs.sdk-home }} steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false + sparse-checkout: | + /src/sdk/package.json + /script/sea-build.ts + /package.json + /nodejs/package.json + sparse-checkout-cone-mode: false - id: detect run: | if [[ -f src/sdk/package.json && -f script/sea-build.ts ]]; then @@ -60,7 +205,6 @@ jobs: needs: detect-layout if: github.event_name != 'merge_group' && needs.detect-layout.outputs.runtime-source == 'checkout' runs-on: ubuntu-latest-xl - timeout-minutes: 60 concurrency: group: windows-x64-addons-release-windows-e2e-no-icf-${{ github.sha }} queue: max @@ -70,7 +214,6 @@ jobs: packages: read steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false @@ -100,7 +243,7 @@ jobs: - uses: ./.github/actions/setup-node if: steps.cache.outputs.cache-hit != 'true' - timeout-minutes: ${{ fromJSON(env.SETUP_NODE_TIMEOUT_MINUTES) }} + timeout-minutes: 60 - uses: ./.github/actions/setup-bazel if: steps.cache.outputs.cache-hit != 'true' with: @@ -210,7 +353,6 @@ jobs: artifact: Linux-X64-gnu bazel-config: e2e-no-lto shared-cli-build-compatible: true - timeout-minutes: 60 secrets: inherit build-runtime-linuxmusl-x64: @@ -230,7 +372,25 @@ jobs: target: linuxmusl-x64 artifact: Linux-X64-musl bazel-config: e2e-no-lto - timeout-minutes: 60 + secrets: inherit + + build-runtime-linuxmusl-arm64: + name: "Build runtime (linuxmusl-arm64)" + needs: detect-layout + if: github.event_name != 'merge_group' + permissions: + actions: read + contents: read + id-token: write + packages: read + uses: ./.github/workflows/sdk-runtime-artifact.yml + with: + runtime-source: ${{ needs.detect-layout.outputs.runtime-source }} + sdk-home: ${{ needs.detect-layout.outputs.sdk-home }} + os: ubuntu-latest-xl + target: linuxmusl-arm64 + artifact: Linux-ARM64-musl + bazel-config: e2e-no-lto secrets: inherit build-runtime-darwin-arm64: @@ -246,13 +406,12 @@ jobs: with: runtime-source: ${{ needs.detect-layout.outputs.runtime-source }} sdk-home: ${{ needs.detect-layout.outputs.sdk-home }} - os: macos-latest-xlarge + os: macos-26-xlarge-agent-runtime target: darwin-arm64 artifact: macOS-ARM64 bazel-config: e2e-no-lto use-bazel-addons-on-darwin: true shared-cli-build-compatible: true - timeout-minutes: 60 secrets: inherit build-runtime-win32-x64: @@ -274,7 +433,6 @@ jobs: bazel-config: windows-e2e-no-icf shared-cli-build-compatible: true prebuilt-addons-artifact: ${{ needs.detect-layout.outputs.runtime-source == 'checkout' && 'sdk-bazel-cross-addons-win32-x64-release' || '' }} - timeout-minutes: 60 secrets: inherit sdk-linux-x64: @@ -296,6 +454,16 @@ jobs: sdk-home: ${{ needs.detect-layout.outputs.sdk-home }} secrets: inherit + sdk-linuxmusl-arm64: + name: "Linux musl ARM64 (Java)" + needs: [detect-layout, build-runtime-linuxmusl-arm64] + if: github.event_name != 'merge_group' + uses: ./.github/workflows/sdk-java.yml + with: + platform: linuxmusl-arm64 + sdk-home: ${{ needs.detect-layout.outputs.sdk-home }} + secrets: inherit + sdk-darwin-arm64: name: "macOS ARM64" needs: [detect-layout, build-runtime-darwin-arm64] @@ -317,40 +485,35 @@ jobs: sdk-home: ${{ needs.detect-layout.outputs.sdk-home }} secrets: inherit - sdk-docs: - name: "Documentation" - needs: detect-layout - if: github.event_name != 'merge_group' - uses: ./.github/workflows/sdk-platform.yml - with: - platform: docs - sdk-home: ${{ needs.detect-layout.outputs.sdk-home }} - secrets: inherit - + # Only Linux CAPI gates this rollup; the full SDK aggregate still reports all coverage. sdk-typescript: name: sdk-typescript if: always() - needs: [sdk-linux-x64, sdk-linuxmusl-x64, sdk-darwin-arm64, sdk-win32-x64] + needs: [detect-sdk-changes, sdk-linux-x64] runs-on: ubuntu-slim steps: - - name: Check Node.js SDK results + - name: Check Linux CAPI Node.js SDK result env: + DETECT_RESULT: ${{ needs.detect-sdk-changes.result }} EVENT_NAME: ${{ github.event_name }} + HAS_SDK_CHANGES: ${{ needs.detect-sdk-changes.outputs.has_sdk_changes }} RESULTS: ${{ toJSON(needs) }} run: | - for job in sdk-linux-x64 sdk-linuxmusl-x64 sdk-darwin-arm64 sdk-win32-x64; do - expected=success - result=$(jq -r --arg job "$job" '.[$job].outputs["nodejs-result"]' <<< "$RESULTS") - # TEMPORARY MERGE QUEUE REDUCTION: only Linux x64 runs in merge groups. - if [[ "$EVENT_NAME" == "merge_group" && "$job" != "sdk-linux-x64" ]]; then - expected=skipped - result=$(jq -r --arg job "$job" '.[$job].result' <<< "$RESULTS") - fi - if [[ "$result" != "$expected" ]]; then - echo "::error::Node.js SDK job $job: expected $expected, got $result" + linux_result=$(jq -r '.["sdk-linux-x64"].result' <<< "$RESULTS") + if [[ "$EVENT_NAME" == "pull_request" && "$DETECT_RESULT" == "success" && "$HAS_SDK_CHANGES" == "false" ]]; then + if [[ "$linux_result" != "skipped" ]]; then + echo "::error::Non-SDK pull request did not skip sdk-linux-x64: $linux_result" exit 1 fi - done + echo "No SDK-impacting changes; Linux CAPI Node.js SDK job skipped" + exit 0 + fi + + result=$(jq -r '.["sdk-linux-x64"].outputs["nodejs-capi-result"]' <<< "$RESULTS") + if [[ "$result" != "success" ]]; then + echo "::error::Linux CAPI Node.js SDK job: expected success, got $result" + exit 1 + fi check-freshness: name: "Check schema and SDK freshness" @@ -361,13 +524,34 @@ jobs: id-token: write steps: - uses: actions/checkout@v7 - timeout-minutes: 10 with: persist-credentials: false - fetch-depth: 0 + fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 1 }} + - name: Fetch generation comparison baseline + if: needs.detect-layout.outputs.runtime-source == 'checkout' && (github.event_name == 'merge_group' || github.event_name == 'push') + env: + BASELINE_SHA: ${{ github.event.merge_group.base_sha || github.event.before }} + CHECKOUT_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if [[ "$GITHUB_EVENT_NAME" == "push" && "$BASELINE_SHA" =~ ^0+$ ]]; then + echo "New branch push has no generation baseline; checking all projections." + exit 0 + fi + if [[ ! "$BASELINE_SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then + echo "::error::Missing or invalid SDK generation baseline SHA." + exit 1 + fi + if git cat-file -e "$BASELINE_SHA^{commit}" 2>/dev/null; then + exit 0 + fi + auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')" + GIT_CONFIG_COUNT=1 \ + GIT_CONFIG_KEY_0=http.https://github.com/.extraheader \ + GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $auth_header" \ + git fetch --no-tags --depth=1 origin "$BASELINE_SHA" - if: needs.detect-layout.outputs.runtime-source == 'checkout' uses: ./.github/actions/setup-node - timeout-minutes: ${{ fromJSON(env.SETUP_NODE_TIMEOUT_MINUTES) }} with: install-deps: "false" - if: needs.detect-layout.outputs.runtime-source == 'checkout' @@ -433,26 +617,45 @@ jobs: name: "SDK" if: always() needs: + - detect-sdk-changes - build-runtime-windows-x64-addons - build-runtime-linux-x64 - build-runtime-linuxmusl-x64 + - build-runtime-linuxmusl-arm64 - build-runtime-darwin-arm64 - build-runtime-win32-x64 - detect-layout - sdk-linux-x64 - sdk-linuxmusl-x64 + - sdk-linuxmusl-arm64 - sdk-darwin-arm64 - sdk-win32-x64 - - sdk-docs - check-freshness runs-on: ubuntu-slim steps: - name: Check SDK results env: + DETECT_RESULT: ${{ needs.detect-sdk-changes.result }} EVENT_NAME: ${{ github.event_name }} + HAS_SDK_CHANGES: ${{ needs.detect-sdk-changes.outputs.has_sdk_changes }} RESULTS: ${{ toJSON(needs) }} RUNTIME_SOURCE: ${{ needs.detect-layout.outputs.runtime-source }} run: | + if [[ "$EVENT_NAME" == "pull_request" && "$DETECT_RESULT" == "success" && "$HAS_SDK_CHANGES" == "false" ]]; then + unexpected=$(jq -r ' + to_entries[] + | select(.key != "detect-sdk-changes" and .value.result != "skipped") + | "\(.key): \(.value.result)" + ' <<< "$RESULTS") + if [[ -n "$unexpected" ]]; then + echo "::error::Non-SDK pull request did not skip all SDK jobs:" + echo "$unexpected" + exit 1 + fi + echo "No SDK-impacting changes; SDK build and test matrix skipped" + exit 0 + fi + # TEMPORARY MERGE QUEUE REDUCTION: keep this branch aligned with the # gated jobs above until the full merge-group matrix is restored. if [[ "$EVENT_NAME" == "merge_group" ]]; then @@ -465,12 +668,13 @@ jobs: skipped_jobs=( build-runtime-windows-x64-addons build-runtime-linuxmusl-x64 + build-runtime-linuxmusl-arm64 build-runtime-darwin-arm64 build-runtime-win32-x64 sdk-linuxmusl-x64 + sdk-linuxmusl-arm64 sdk-darwin-arm64 sdk-win32-x64 - sdk-docs ) for job in "${required_jobs[@]}"; do if [[ "$(jq -r --arg job "$job" '.[$job].result' <<< "$RESULTS")" != "success" ]]; then @@ -501,6 +705,7 @@ jobs: failures=$(jq -r --arg runtime_source "$RUNTIME_SOURCE" ' to_entries[] | select(.value.result != "success") + | select(.key != "detect-sdk-changes") | select( $runtime_source != "published" or .key != "build-runtime-windows-x64-addons" diff --git a/BUILD.bazel b/BUILD.bazel index e25b8ef8e3..b9465c7090 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,9 +1,15 @@ +exports_files( + ["test/harness/sdk-diagnostics.mjs"], + visibility = ["//src/runtime-bin:__pkg__"], +) + SHARED_CODEGEN_INPUTS = [ "nodejs/scripts/releaseArtifacts.ts", "nodejs/src/cliVersion.ts", "scripts/codegen/legacy-parameters.ts", "scripts/codegen/package-lock.json", "scripts/codegen/package.json", + "scripts/codegen/extensible-enums.ts", "scripts/codegen/utils.ts", "scripts/runtime-layout.mjs", "scripts/runtime-release.mjs", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e64a0bb04..6513793b66 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -316,7 +316,12 @@ additional feature/acquisition choices documented in [rust/AGENTS.md](rust/AGENT ### Documentation checks -API snippet validation is separate from SDK tests. From the SDK root: +[SDK CI](.github/workflows/sdk.yml) validates Node.js, Python, Go, .NET, and Java +API snippets after successful tests in their standard Linux jobs (JDK 25 for Java). +These checks run on pull requests, pushes to `main`, and manual workflow runs, +but not merge groups. A documentation failure fails the corresponding language job. + +To validate snippets without running SDK tests, run these commands from the SDK root: ```bash npm --prefix scripts/docs-validation ci @@ -327,8 +332,15 @@ uv run --locked --project python npm run docs:python ``` This extracts and validates snippets for Node.js, Python, Go, .NET, or Java. -Java's current docs validator calls `mvn` directly, -so this task also needs Maven 3.9+ on PATH. There is no `docs:rust` facade; +`docs:java` installs the SDK once through its Maven wrapper, with tests, replay +harness setup, and native downloads disabled, then compiles the snippets using +the same wrapper. CI supplies that installation in its existing post-test step; +the validator does not reinstall it. A separate Maven installation is not required. +Java validation also compiles the exact [README Quick Start](java/README.md#quick-start). +The regular Maven integration suite checks a standalone consumer JAR with a manifest +classpath and runtime dependencies, without a live model, credentials, or native runtime. +These checks replace the former agent-driven Java smoke workflow. +There is no `docs:rust` facade; follow [the Rust SDK workflow](.github/workflows/sdk-rust.yml) for rustdoc. ### Recording and replaying SDK tests @@ -344,12 +356,18 @@ For TypeScript SDK E2Es, use the existing `nodejs/test/e2e/harness/sdkTestContext.ts` fixture. In the runtime repository, also follow the `e2e-test-author` skill's SDK section. -SDK CI runs full subprocess coverage followed by a short in-process smoke -step on the same runner wherever both modes share a platform. Smoke still -runs if the subprocess tests fail, and either failure fails the job. Java's -macOS, Windows, and musl smoke jobs remain separate because they have no -matching subprocess job. Merge groups retain the reduced Linux TypeScript -CAPI subprocess coverage. +All SDKs run full subprocess coverage and in-process smoke on Linux/glibc +x64, macOS ARM64, Windows x64, and Linux/musl x64. Windows .NET uses complementary +jobs per framework. Smoke also runs after subprocess failures; either failure +fails the job. Java uses JDK 25 on these platforms, +plus a Linux/glibc JDK 17 compatibility job using precompiled classes. +Merge groups retain the reduced Linux TypeScript CAPI subprocess coverage. + +The `sdk-typescript` required rollup checks only the Linux CAPI job, including +its build, packaging, and applicable static checks. Other platforms, BYOK +backends, and languages keep their existing scheduling and failure reporting; +they do not gate this rollup. The full `SDK` aggregate still requires all +scheduled coverage to succeed. The three BYOK backend sweeps run in separate Linux TypeScript jobs, alongside the normal CAPI job; they do not repeat unit tests, packaging, or static @@ -390,6 +408,12 @@ failed-startup cleanup. Keep those lifecycle expectations aligned when changing an SDK transport; test watchdogs must allow all cleanup phases their separate budgets, rather than treating the graceful-exit timeout as a total shutdown cap. +Java also exercises the opt-in `shutdown-error` mode. It rejects +`runtime.shutdown`, writes `.eof` when stdin closes, and holds +cleanup-marker creation and process exit until the test creates +`.release`. This handshake verifies that a failed shutdown RPC +still allows EOF-driven finalization before forced cleanup. + The shared harness records real inference responses under `test/snapshots`. Record new captures with `GITHUB_TOKEN` set and `GITHUB_ACTIONS` unset; never author model responses by hand. Rerun with `GITHUB_ACTIONS=true` and real diff --git a/docs/developer-docs/secrets.md b/docs/developer-docs/secrets.md index 1218f96254..b09ddd213c 100644 --- a/docs/developer-docs/secrets.md +++ b/docs/developer-docs/secrets.md @@ -17,7 +17,7 @@ These secrets are used by the authoritative SDK build/test workflow. These secrets power the GitHub Agentic Workflows (gh-aw) used for issue triage, code generation, and release automation. * **`COPILOT_GITHUB_TOKEN`**: GitHub OAuth token consumed by the Copilot CLI for AI authentication. Required by all agentic workflows when invoking `copilot` for AI inference. - * Workflows: `issue-triage.lock.yml`, `issue-classification.lock.yml`, `handle-bug.lock.yml`, `handle-enhancement.lock.yml`, `handle-question.lock.yml`, `handle-documentation.lock.yml`, `java-codegen-check.yml`, `java-codegen-fix.lock.yml`, `java-smoke-test.yml`, `java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml`, `release-changelog.lock.yml`, `cross-repo-issue-analysis.lock.yml` + * Workflows: `issue-triage.lock.yml`, `issue-classification.lock.yml`, `handle-bug.lock.yml`, `handle-enhancement.lock.yml`, `handle-question.lock.yml`, `handle-documentation.lock.yml`, `java-codegen-check.yml`, `java-codegen-fix.lock.yml`, `java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml`, `release-changelog.lock.yml`, `cross-repo-issue-analysis.lock.yml` * **`GH_AW_GITHUB_TOKEN`**: Optional GitHub token override for repository operations (reading code, creating pull requests, and making GitHub API calls). If unset, workflows use the automatic `GITHUB_TOKEN`. * Workflows: `issue-triage.lock.yml`, `issue-classification.lock.yml`, `handle-bug.lock.yml`, `handle-enhancement.lock.yml`, `handle-question.lock.yml`, `handle-documentation.lock.yml`, `java-codegen-fix.lock.yml`, `java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml`, `release-changelog.lock.yml`, `cross-repo-issue-analysis.lock.yml` diff --git a/docs/features/custom-agents.md b/docs/features/custom-agents.md index 9e2f597688..965582a01b 100644 --- a/docs/features/custom-agents.md +++ b/docs/features/custom-agents.md @@ -25,6 +25,8 @@ flowchart TD ## Defining custom agents +To discover Markdown definitions from versioned packages or vendored folders, use `agentDirectories` or [repository customization locations](./customization-locations.md). + Pass `customAgents` when creating a session. Each agent needs at minimum a `name` and `prompt`.
diff --git a/docs/features/customization-locations.md b/docs/features/customization-locations.md new file mode 100644 index 0000000000..703c5d5066 --- /dev/null +++ b/docs/features/customization-locations.md @@ -0,0 +1,55 @@ + + +# Customization discovery locations + +GitHub Copilot can discover versioned skills, agents, instructions, and file hooks directly from package installations, submodules, and vendored directories. You don't need to copy them into conventional directories. + +## Repository settings + +Declare checkout-relative directories in `.github/copilot/settings.json`: + +```json +{ + "skillDirectories": ["node_modules/@example/team/skills"], + "agentDirectories": ["vendor/team/agents"], + "instructionDirectories": ["vendor/team/instructions"], + "hookDirectories": ["vendor/team/hooks"] +} +``` + +Each list adds discovery locations for its own customization type. Conventional locations continue to work. A key in `.github/copilot/settings.local.json` replaces only that repository list; an empty list removes its repository contribution. Omitted keys inherit the checked-in list. Repository lists don't replace SDK inputs or existing user skill directories. + +Repository paths must be nonempty, literal directories within the declaring checkout. Absolute paths, home or environment-variable expansion, globs, and escapes outside the checkout are rejected. Links and junctions are allowed only when their resolved roots and discovered descendants remain inside the checkout. A missing directory is reported and can be discovered after installation and an explicit customization reload. Copilot doesn't install packages or watch these directories. + +File content from repository-defined discovery locations is read through a validated, opened file handle. Retargeting a link outside the checkout between discovery and invocation doesn't authorize reading its new target. + +Repository locations require trust covering the declaring checkout root and remain subject to each customization type's existing discovery switches, disabled entries, and managed policy. Persisted trust for only a subdirectory doesn't authorize its parent checkout's settings. Listing a location doesn't enable a disabled customization type or grant filesystem access. + +In the CLI, remembered folder trust refreshes repository customizations in the current session, even if model catalog initialization failed. `/skills reload` also rechecks persisted trust and repository discovery settings. + +## SDK inputs + +Session creation, resume, and option updates accept the same four lists. TypeScript and Java use `skillDirectories`, `agentDirectories`, `instructionDirectories`, and `hookDirectories`. Python and Rust use snake case; Go and .NET use Pascal case. + +SDK directories can be outside the checkout. Leading and trailing whitespace is trimmed, and blank entries are ignored. Relative SDK paths resolve once against the request's effective working directory when supplied. Changing the working directory doesn't move retained SDK roots. Supplying a new relative list uses the new effective working directory. An empty list clears only the explicit SDK contribution; omission or `null` leaves it unchanged during an update. + +If adopting a `hookDirectories` replacement fails or is canceled before the new hook service takes ownership, the previous directory option and live hook service remain in place. Overlapping failed updates restore the retained value rather than another failed update's directories. A failed update doesn't roll back a newer accepted update. + +Explicit agent and file-hook directories don't require ambient configuration discovery. `enableFileHooks` controls repository-origin hooks, including conventional `.github/hooks`, but not explicit SDK hook directories or callback `hooks`. Managed restrictions and hook disables still apply. + +Directory inputs are discovery configuration, not general filesystem grants. They don't widen `additionalDirectories`. Existing file-hook sandbox rules remain in effect. + +Loading active local skills adds read-only grants for their contributing SDK skill directories under the runtime's skill-resource policy. Empty, ignored, and disabled skill sources don't add those grants. Repository-defined skill directories don't add them. + +## File formats and precedence + +| Type | Discovered content | +| --- | --- | +| Skills | A direct `SKILL.md` bundle or recursively discovered topmost bundles | +| Agents | Existing Markdown agent definitions | +| Repository instructions | Recursive `*.instructions.md` files, with existing frontmatter and `applyTo` matching | +| Hooks | Existing hook JSON configurations | + +Repository instruction directories don't import package `AGENTS.md` hierarchies or `.claude/rules`. Existing SDK instruction-directory formats remain supported. Each subsystem preserves its existing source precedence. Overlapping hook file references are deduplicated; distinct authored actions aren't collapsed because their commands happen to match. + +File-backed command hooks receive `COPILOT_HOOK_DIR`, the directory containing their configuration file. Use it to locate adjacent scripts and resources. Hook working-directory semantics don't change: they remain anchored to the consuming workspace. `COPILOT_HOOK_DIR` is an execution environment variable, not JSON template expansion; `COPILOT_PLUGIN_ROOT` retains its separate plugin-root behavior. Inline hooks and SDK callbacks don't gain a fabricated configuration directory. diff --git a/docs/features/hooks.md b/docs/features/hooks.md index a3cfc0f503..b0cd89d6e9 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -35,6 +35,55 @@ All hooks are **optional**—register only the ones you need. Returning `null` ( ## Registering hooks +Callback `hooks` remain separate from file-backed `hookDirectories`. For packaged hook configurations and adjacent resources, see [customization discovery locations](./customization-locations.md). + +### Agent-scoped declarative hooks + +Custom agents can declare a `hooks` event map in `.agent.md` frontmatter or in +the SDK's custom-agent configuration. These are declarative command or HTTP +actions, not SDK callback functions. They run only while that agent is selected, +in addition to applicable session, user, repository, plugin, and managed-policy +hooks. Changing or clearing the selected agent changes the scoped hooks for the +next invocation without changing other sessions or concurrent subagents. + +```yaml +--- +name: formatter +description: Formats changed files +hooks: + PostToolUse: + - type: command + command: ./scripts/format-changed-files.sh + windows: ./scripts/format-changed-files.ps1 +--- +Format the files you change. +``` + +Both runtime event names such as `postToolUse` and supported VS Code aliases +such as `PostToolUse` are accepted. `command` supplies the fallback shell command; +`windows`, `linux`, and `osx` override it on the corresponding platform. Hook +commands are relative to the executing session's repository root, unless they +set an explicit working directory. Hook payloads and decisions follow the +runtime's existing hook contracts. + +When a local agent runs as a subagent, its scoped `Stop` (`agentStop`) actions +run at `SubagentStop` instead of ordinary turn stop. An explicit `SubagentStop` +action on that agent still observes its own children. Stop callbacks receive +`stop_hook_active: true` after a prior block. After eight consecutive scoped +Stop continuations, the runtime ignores further scoped blocks and accepts the +child's final response unless a parent lifecycle hook still blocks completion. + +Repository and inherited-agent hooks require workspace admission. Agent +discovery or selection does not itself grant trust. Existing hook-disable +settings, enterprise restrictions, sandbox permissions, and timeouts also apply +to scoped actions. SDK-provided agents cannot claim managed-plugin privileges. +Remote or organization-hosted agent definitions do not execute scoped hooks, +and scoped Stop dispatch is supported for local runtime subagents, not external +AHP participants. + +Unsupported event names are reported before event selection. Action preparation +errors affect only their declared event; shared and managed-policy hooks still run. + Pass a `hooks` object when you create (or resume) a session. Every example below follows this pattern.
diff --git a/docs/features/mcp.md b/docs/features/mcp.md index cf3003ce8c..1c93c82710 100644 --- a/docs/features/mcp.md +++ b/docs/features/mcp.md @@ -26,6 +26,44 @@ The SDK supports two types of MCP servers: ## Configuration +### Inspect configuration and lifecycle + +`session.rpc.mcp.listConfigured()` is a parameterless, passive inventory read. +It does not start or restart servers, authenticate, apply sandbox policy, or +wait for server startup. Configuration discovery and policy filtering determine +which servers appear and their `enabled` values. + +This experimental RPC requires an aligned SDK/runtime release. Its earlier +prerelease response allowed `live` to be omitted; SDKs using the required +lifecycle contract do not support that older response shape. When supplying +an external runtime, update it alongside the SDK. The overall protocol version +is unchanged and does not identify this experimental contract revision. + +Every entry includes `live.status`. A configured server with no materialized +runtime server reports the existing `not_configured` status, even when +`enabled` is `true`. A runtime server that was explicitly stopped reports +`stopped`. Materialized servers report their actual lifecycle, including +`pending`, `connected`, `needs-auth`, and `failed`; failures include `live.error` +when available. + +Configuration and lifecycle describe different facts. If a server's URL, +authentication, or configuration source changes while an old connection remains +alive, inventory still reports that connection's actual lifecycle. A +`connected` status does not mean the latest configuration has been applied. +The runtime owns this observation; clients must not substitute cached state +based only on the server name. + +Inventory retries concurrent graph replacement a bounded number of times and +returns an error if it cannot obtain a consistent snapshot. It never omits +`live` to hide a graph race. + +A name-only `startServer` or `restartServer` resolves and initializes only the +requested server after a cold session resume without first calling `list`. +This includes user and plugin configurations and the built-in GitHub server +configured through `githubMcpToolConfig`. It does not start other configured +servers or override disabled state, authentication requirements, sandbox policy, +or configuration-source precedence. + ### Node.js / TypeScript ```typescript diff --git a/docs/features/plugin-directories.md b/docs/features/plugin-directories.md index 456ef88e7f..393fc4c048 100644 --- a/docs/features/plugin-directories.md +++ b/docs/features/plugin-directories.md @@ -422,6 +422,63 @@ for (const plugin of plugins.plugins) { 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. +## Retrying plugins required by managed settings + +When managed settings require plugins through `enabledPlugins`, the runtime installs or updates them before chat messages. If that fails, the session emits a `session.warning` with `warningType: "managed_plugins"` and waits an hour, or until the managed settings change, before trying again. The experimental `session.rpc.plugins.retryManaged()` tries again right away, for example from a Retry action next to that warning. + +Call it with no arguments to retry every plugin the managed settings require, or pass `plugin@marketplace` specs in `plugins` to retry only those. The result has one entry per plugin with a `status`: `installed`, `updated`, `already_present`, `failed`, `deferred`, or `not_required`. `failed` and `deferred` entries include an `error`. The session also emits the usual `session.info` progress and `session.warning` failure events. + +
+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" }), + }); + + // Retry every plugin the managed settings require, for example from a Retry action. + const result = await session.rpc.plugins.retryManaged(); + for (const entry of result.plugins) { + console.log(`${entry.spec}: ${entry.status}${entry.error ? ` (${entry.error})` : ""}`); + } + + // Or retry only the required plugins that are still missing. + const { plugins } = await session.rpc.plugins.list(); + const missing = plugins + .filter((plugin) => plugin.managedDesiredEnabled === true && plugin.installed === false) + .map((plugin) => `${plugin.name}@${plugin.marketplace}`); + await session.rpc.plugins.retryManaged({ plugins: missing }); +} + +main(); +``` + + +```typescript +// Retry every plugin the managed settings require, for example from a Retry action. +const result = await session.rpc.plugins.retryManaged(); +for (const entry of result.plugins) { + console.log(`${entry.spec}: ${entry.status}${entry.error ? ` (${entry.error})` : ""}`); +} + +// Or retry only the required plugins that are still missing. +const { plugins } = await session.rpc.plugins.list(); +const missing = plugins + .filter((plugin) => plugin.managedDesiredEnabled === true && plugin.installed === false) + .map((plugin) => `${plugin.name}@${plugin.marketplace}`); +await session.rpc.plugins.retryManaged({ plugins: missing }); +``` + +
+ +Runtimes that do not prepare managed plugins for the session reject the call. + ## 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`. diff --git a/docs/features/session-persistence.md b/docs/features/session-persistence.md index 302844b347..d3826e4f2b 100644 --- a/docs/features/session-persistence.md +++ b/docs/features/session-persistence.md @@ -131,6 +131,34 @@ await session.SendAndWaitAsync(new MessageOptions { Prompt = "Analyze my codebas Later—minutes, hours, or even days—you can resume the session from where you left off. +### Remembered permissions with a session filesystem + +When you configure a custom `sessionFs` provider, runtime-owned durable permission choices use provider storage rather than the runtime host's configuration. The files live under the provider's `sessionStatePath` and retain their existing formats: + +* `permissions.json`: A top-level `locations` map retaining the existing `tool_approvals` and `allowed_directories` fields +* `settings.json`: Top-level `allowedUrls` for `approve-permanently` URL approvals and `sandbox` for saved sandbox preferences +* `config.json`: Top-level `trustedFolders` for remembered folder trust and `sandboxOnboardingShown` for the first-enable sandbox message + +Location keys are normalized provider directory paths, such as `/workspace`, without an added prefix. The runtime resolves them lexically using provider path conventions, without inspecting the host filesystem or discovering host Git repositories. An approval saved for `/workspace` is not automatically selected when the working directory is `/workspace/sub`. + +Provider-backed folder trust also uses lexical paths: a trusted folder covers itself and its descendants, not linked Git worktrees at other paths. Trust those worktree paths explicitly. + +There is no additional session-ID partition inside these files. Sessions that access the same backing files share remembered choices. Use separate provider namespaces when sessions or tenants must not share grants. With a namespace per session, permanent choices survive that session's resumes but do not automatically carry over to new sessions. To restore a session's persisted choices on resume, reconnect it to the same namespace. + +Consent updates are serialized per provider endpoint and file within one runtime process. Separate endpoints do not block each other. If different provider endpoints or runtime processes share backing files, the application must coordinate concurrent updates; the runtime cannot infer that those files are shared. + +These operations never import, update, or fall back to the host's `permissions-config.json`, `settings.json`, or `config.json`, including when provider reads or writes fail. Existing-format files supplied through the provider are read directly. + +As with host configuration, URL approvals are read only from `settings.json`. A legacy `allowedUrls` field in `config.json` is ignored; `config.json` remains the global-state file for remembered folder trust and the sandbox onboarding marker. + +Storage routing does not change permission lifetimes, URL denial precedence, or session policy behavior. Approve-once and approve-for-session do not become permanent grants. + +Saved sandbox preferences are restored on create and resume. Later explicit SDK `options.update` calls can change the live sandbox configuration without rewriting the saved preference. + +Without `sessionFs`, SDK applications in both `empty` and `copilot-cli` modes retain existing host-backed persistence. This includes the existing behavior where permanent URL consent saves host settings and grants access in the live session, but a fresh SDK session does not automatically load the host URL allowlist. + +See [Multi-tenancy and server deployments](../setup/multi-tenancy.md#sessionfs) for provider isolation responsibilities. + ### Transcript recovery The resume option `allowTranscriptRecovery` controls recovery when the runtime loads a @@ -283,7 +311,17 @@ When resuming a session, you can optionally reconfigure many settings. This is u With `model: "auto"`, the optional `capi.autoTier` setting selects an Auto routing preference: `efficiency`, `balance`, `intelligence`, or `fast`. In Python, use `capi={"auto_tier": "balance"}`. This setting applies to V2 Auto routing; V1 Auto requests are unchanged. -`fast` is an integrator-only latency preset, not a first-party GitHub Copilot product preference. The SDK does not decide Fast eligibility, inspect client identity, choose it as a default, or fall back to another tier when a runtime does not support it—an older runtime returns its native error unchanged. +When the runtime's default-off `DYNAMIC_AUTO_TIERS` feature is enabled, the session's `model.list` RPC also returns optional `auto` metadata from the provider's `/meta` endpoint. Use the enabled descriptors with `type: "auto"` to discover additional supported tier identifiers, their display names, descriptions, and ordering. The existing selection methods and JSON fields accept these identifiers. A discovery failure does not fall back to `/models`, and a successful response without `auto` metadata provides no selectable Auto tiers. + +Treat tier identifiers as extensible values, not a closed enumeration. Existing named values remain available; for additional identifiers, use strings in Node.js and Python, `AutoTier("premium-v2")` in Go, `new AutoTier("premium-v2")` in .NET, `AutoTier::Custom` in Rust, or `AutoTier.fromValue` in Java. The provider's `defaultTier` describes its default routing without creating a committed SDK preference. + +If a persisted tier is removed or disabled, resume preserves the explicit preference rather than replacing it with the provider's default. Select an available replacement before activating Auto routing. + +The CLI also preserves settings-derived preferences during startup, even when a tier is unavailable or dynamic discovery is disabled. You can then select a replacement in the model picker. Explicit SDK create and resume preferences are still validated before the operation succeeds, and Auto activation always validates availability against the resolved discovery mode. + +When a create or resume request includes `expAssignments`, the runtime installs those assignments before validating an explicit Auto preference. Validation, discovery, and activation use the same resolved feature decision. + +`fast` is an integrator-only latency preset, not a first-party GitHub Copilot product preference. Fast is not validated against the `/meta` tier catalog when configuring a session. The SDK does not decide Fast eligibility, inspect client identity, choose it as a default, or fall back to another tier when a runtime does not support it—an older runtime returns its native error unchanged. The runtime persists the selected tier, so applications do not need to resend it on every resume: @@ -309,6 +347,8 @@ if (result.status === "pending") { The runtime does not apply the preference immediately. It records the request and commits it only when a later user turn using the `auto` model successfully obtains a usable model from the provider. A `pending` status therefore confirms that the request was accepted, not that it took effect. Only the most recent request survives: a new request replaces any earlier one that no turn has claimed yet. +If an older request is still validating when a newer preference request or reset arrives, the older call fails with a superseded-request error instead of replacing the newer intent. + Watch for the outcome through these events: * `session.model_change` when the preference commits. diff --git a/docs/features/skills.md b/docs/features/skills.md index 30c5112dbd..df8d319928 100644 --- a/docs/features/skills.md +++ b/docs/features/skills.md @@ -336,6 +336,333 @@ The frontmatter fields: The markdown body contains the instructions that are injected into the session context when the skill is loaded. +## Skill providers (experimental) + +> [!NOTE] +> Skill providers are experimental. The API can change in future SDK releases. + +A skill provider serves skills from your application's own storage, such as a database in a multi-tenant service, instead of `SKILL.md` files on disk. Provider skills join the session's skill catalog alongside file-based skills. The model loads them on demand through the `skill` tool, and users can invoke them like any other skill. + +A provider implements two operations: + +* **List skills**: returns catalog metadata for every skill: a `name`, a `description`, and optionally `userInvocable`, `disableModelInvocation`, and `argumentHint`. The runtime calls it when it loads the session's skills. +* **Read skill**: returns the markdown for one skill, or a not-found result if the skill no longer exists. The runtime calls it only when the skill is loaded. + +Pass the provider when you create or resume a session: + +
+Node.js / TypeScript + +```typescript +import { approveAll, CopilotClient, type SkillProvider } from "@github/copilot-sdk"; + +const releaseSkills = new Map([ + [ + "release-notes", + { + description: "Writes release notes in the team's format.", + markdown: "Group changes by feature area and link each pull request.", + }, + ], +]); + +const skillProvider: SkillProvider = { + listSkills: () => + [...releaseSkills].map(([name, skill]) => ({ name, description: skill.description })), + readSkill: (name) => releaseSkills.get(name)?.markdown ?? null, +}; + +const client = new CopilotClient(); +const session = await client.createSession({ + onPermissionRequest: approveAll, + skillProvider, +}); +``` + +
+
+Python + +```python +from copilot import CopilotClient, SkillProviderDescriptor +from copilot.session import PermissionHandler + +RELEASE_SKILLS = { + "release-notes": ( + "Writes release notes in the team's format.", + "Group changes by feature area and link each pull request.", + ), +} + + +class ReleaseSkills: + async def list_skills(self) -> list[SkillProviderDescriptor]: + return [ + SkillProviderDescriptor(name=name, description=description) + for name, (description, _) in RELEASE_SKILLS.items() + ] + + async def read_skill(self, name: str) -> str | None: + skill = RELEASE_SKILLS.get(name) + return skill[1] if skill else None + + +async def main(): + client = CopilotClient() + await client.start() + session = await client.create_session( + on_permission_request=PermissionHandler.approve_all, + skill_provider=ReleaseSkills(), + ) +``` + +
+
+Go + +```go +package main + +import ( + "context" + "fmt" + "log" + + copilot "github.com/github/copilot-sdk/go" + "github.com/github/copilot-sdk/go/rpc" +) + +type releaseSkill struct { + description string + markdown string +} + +type releaseSkills map[string]releaseSkill + +func (s releaseSkills) ListSkills(ctx context.Context) ([]rpc.SkillProviderDescriptor, error) { + descriptors := make([]rpc.SkillProviderDescriptor, 0, len(s)) + for name, skill := range s { + descriptors = append(descriptors, rpc.SkillProviderDescriptor{Name: name, Description: skill.description}) + } + return descriptors, nil +} + +func (s releaseSkills) ReadSkill(ctx context.Context, name string) (string, error) { + skill, ok := s[name] + if !ok { + return "", fmt.Errorf("%w: %s", copilot.ErrSkillNotFound, name) + } + return skill.markdown, nil +} + +func main() { + ctx := context.Background() + client := copilot.NewClient(nil) + session, err := client.CreateSession(ctx, &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: releaseSkills{ + "release-notes": { + description: "Writes release notes in the team's format.", + markdown: "Group changes by feature area and link each pull request.", + }, + }, + }) + if err != nil { + log.Fatal(err) + } + _ = session +} +``` + +
+
+.NET + +```csharp +#pragma warning disable GHCP001 // Skill providers are experimental. +using GitHub.Copilot; +using GitHub.Copilot.Rpc; + +public sealed class ReleaseSkills : ISkillProvider +{ + private readonly Dictionary _skills = new() + { + ["release-notes"] = ( + "Writes release notes in the team's format.", + "Group changes by feature area and link each pull request."), + }; + + public Task> ListSkillsAsync(CancellationToken cancellationToken) => + Task.FromResult>( + _skills.Select(skill => new SkillProviderDescriptor + { + Name = skill.Key, + Description = skill.Value.Description, + }).ToList()); + + public Task ReadSkillAsync(string name, CancellationToken cancellationToken) => + Task.FromResult(_skills.TryGetValue(name, out var skill) ? skill.Markdown : null); +} + +public static class SkillProviderExample +{ + public static async Task RunAsync(CopilotClient client) + { + await using var session = await client.CreateSessionAsync(new SessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + SkillProvider = new ReleaseSkills(), + }); + } +} +``` + +The .NET skill provider types raise the `GHCP001` experimental diagnostic. Suppress it with `#pragma warning disable GHCP001` or a project-level `GHCP001`. + +
+
+Java + +```java +import com.github.copilot.AllowCopilotExperimental; +import com.github.copilot.CopilotClient; +import com.github.copilot.CopilotSession; +import com.github.copilot.SkillProvider; +import com.github.copilot.SkillProviderDescriptor; +import com.github.copilot.rpc.PermissionHandler; +import com.github.copilot.rpc.SessionConfig; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +@AllowCopilotExperimental +class ReleaseSkills implements SkillProvider { + private final Map markdown = Map.of( + "release-notes", "Group changes by feature area and link each pull request."); + + @Override + public CompletableFuture> listSkills() { + return CompletableFuture.completedFuture(List.of(new SkillProviderDescriptor( + "release-notes", "Writes release notes in the team's format.", null, null, null))); + } + + @Override + public CompletableFuture readSkill(String name) { + return CompletableFuture.completedFuture(markdown.get(name)); + } +} + +@AllowCopilotExperimental +class SkillProviderExample { + static CopilotSession createSession(CopilotClient client) throws Exception { + return client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setSkillProvider(new ReleaseSkills())) + .get(); + } +} +``` + +The Java skill provider API is `@CopilotExperimental`, so the consuming class or method must opt in with `@AllowCopilotExperimental` (or compile with `-Acopilot.experimental.allowed=true`). See [Using experimental APIs](../../java/README.md#using-experimental-apis). + +
+
+Rust + + +```rust +use std::sync::Arc; + +use async_trait::async_trait; +use github_copilot_sdk::{Error, SessionConfig, SkillProvider, SkillProviderDescriptor}; + +struct ReleaseSkills; + +#[async_trait] +impl SkillProvider for ReleaseSkills { + async fn list_skills(&self) -> Result, Error> { + Ok(vec![SkillProviderDescriptor { + name: "release-notes".into(), + description: "Writes release notes in the team's format.".into(), + ..Default::default() + }]) + } + + async fn read_skill(&self, name: &str) -> Result, Error> { + Ok((name == "release-notes") + .then(|| "Group changes by feature area and link each pull request.".to_string())) + } +} + +let session = client + .create_session( + SessionConfig::default() + .approve_all_permissions() + .with_skill_provider(Arc::new(ReleaseSkills)), + ) + .await?; +``` + +
+ +### Provider skill content + +Read skill returns the skill's `SKILL.md` text. YAML frontmatter is optional: + +* Without frontmatter, the whole text is the skill body, and all metadata comes from the listed skill. +* With frontmatter, an omitted field inherits the listed value. A field that you include must match the listed value, or the skill fails to load. +* `allowed-tools` is read only from frontmatter. +* If the first line of the text is `---`, the runtime parses it as frontmatter, so don't start a body-only skill with a Markdown thematic break. + +Provider skills are text-only. They have no base directory, so they can't reference bundled scripts, templates, or other files. `skills.list` reports them with the source `sdk` and an empty `path`. + +### Serving existing SKILL.md files + +To serve `SKILL.md` files that you already have, such as files stored in a database, parse each file's YAML frontmatter once to build its catalog entry, then return the file unchanged from read skill: + +* Map `name` and `description` to the listed skill's `name` and `description`. Both are required in the catalog; the runtime doesn't fall back to a folder name or the skill body. +* Map `user-invocable`, `disable-model-invocation`, and `argument-hint` to the matching optional fields when the frontmatter sets them. +* Return the original text, frontmatter included, from read skill. Because the listed values came from the same frontmatter, they match, and the runtime still reads `allowed-tools` from it. + +### Trusting provider content + +Treat provider skills like skill directories: their content is trusted input. The model follows a skill's instructions, and the frontmatter controls how the skill is invoked. `allowed-tools` doesn't grant permissions in SDK sessions. The runtime reports it in the `allowedTools` field of the `skill.invoked` event, and your permission handler still decides every tool request. + +Don't serve text that end users or other tenants can edit unless you would let them author a skill file. If you build skills from user input, generate the frontmatter yourself instead of passing user-supplied frontmatter through. + +### Provider limits and errors + +The runtime validates the provider's catalog and content: + +* Names must match `^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$` and be unique, ignoring case. +* A catalog can contain at most 1,024 skills and 1 MiB of metadata. Each description and argument hint can be at most 1,024 characters. +* Each skill's markdown can be at most 1 MiB of UTF-8. +* Each call must complete within 30 seconds. When the runtime stops waiting for a call, because it timed out, the session ended, or a resume replaced the provider, it cancels the request and ignores any later result. Each SDK passes that cancellation to your provider in its usual way: + + | SDK | Cancellation signal | + |---|---| + | Node.js | The `signal` (`AbortSignal`) in the options passed to `listSkills` and `readSkill` is aborted. | + | Python | The provider's `asyncio` task is cancelled with `asyncio.CancelledError`. Synchronous providers run to completion. | + | Go | The call's `context.Context` is cancelled. | + | .NET | The call's `CancellationToken` is cancelled. | + | Java | The returned `CompletableFuture` is cancelled with `cancel(true)`, which doesn't interrupt running work. | + | Rust | The provider future is dropped. | + + These signals cover calls that the runtime cancels. When the connection closes or the client is force-stopped, the .NET, Java, and Rust SDKs also cancel calls that are still running. The Node.js, Python, and Go SDKs don't: a running call continues until it returns, and the SDK discards its result. + +If listing fails or returns an invalid catalog, the runtime reports the problem in the `errors` list returned by `skills.reload`. A failed reload keeps the provider skills from the last successful list. If reading a skill fails, the `skill` tool reports a generic load failure to the model. The SDK never forwards the text of errors your provider throws or returns, so that text can't leak into the conversation. + +### Provider lifecycle + +A provider is bound to one session: + +* A provider enables skills unless you set `enableSkills` to `false`, which keeps the provider bound but never called. In `mode: "empty"`, skills stay disabled until you set `enableSkills` to `true`. +* The provider is never persisted. Pass it again when you resume a session. Resuming without a provider removes it from the session. Extensions that join the session don't change it. +* A provider skill with the same name as a file-based skill replaces the file-based skill, and `skills.reload` reports a warning. +* Sub-agents use their parent session's provider. +* The runtime can call the provider concurrently, for example from the `skill` tool, user invocations, and custom agents that preload skills, so both operations must be safe for concurrent use. +* Cloud sessions don't support skill providers. The SDK rejects the configuration before it creates the session. + ## Configuration options ### SessionConfig skill fields @@ -344,12 +671,18 @@ The markdown body contains the instructions that are injected into the session c |----------|-------|------|-------------| | Node.js | `skillDirectories` | `string[]` | Directories to load skills from | | Node.js | `disabledSkills` | `string[]` | Skills to disable | +| Node.js | `skillProvider` | `SkillProvider` | Experimental provider for SDK-supplied skills | | Python | `skill_directories` | `list[str]` | Directories to load skills from | | Python | `disabled_skills` | `list[str]` | Skills to disable | +| Python | `skill_provider` | `SkillProvider` | Experimental provider for SDK-supplied skills | | Go | `SkillDirectories` | `[]string` | Directories to load skills from | | Go | `DisabledSkills` | `[]string` | Skills to disable | +| Go | `SkillProvider` | `SkillProvider` | Experimental provider for SDK-supplied skills | | .NET | `SkillDirectories` | `List` | Directories to load skills from | | .NET | `DisabledSkills` | `List` | Skills to disable | +| .NET | `SkillProvider` | `ISkillProvider` | Experimental provider for SDK-supplied skills | +| Java | `setSkillProvider` | `SkillProvider` | Experimental provider for SDK-supplied skills | +| Rust | `with_skill_provider` | `Arc` | Experimental provider for SDK-supplied skills | ### Built-in skills and `mode: "empty"` diff --git a/docs/features/streaming-events.md b/docs/features/streaming-events.md index 514a8b2b0e..b20339042a 100644 --- a/docs/features/streaming-events.md +++ b/docs/features/streaming-events.md @@ -734,7 +734,7 @@ The `permissionRequest` is a discriminated union on `kind`: | `kind` | Key Fields | Description | |--------|------------|-------------| | `"shell"` | `fullCommandText`, `intention`, `commands[]`, `possiblePaths[]` | Execute a shell command | -| `"write"` | `fileName`, `diff`, `intention`, `newFileContents?` | Write/modify a file | +| `"write"` | `fileName`, `diff`, `intention`, `newFileContents?`, `fileEdits?` | Write/modify a file | | `"read"` | `path`, `intention` | Read a file or directory | | `"mcp"` | `serverName`, `toolName`, `toolTitle`, `args?`, `readOnly` | Call an MCP tool | | `"url"` | `url`, `intention` | Fetch a URL | @@ -743,6 +743,10 @@ The `permissionRequest` is a discriminated union on `kind`: All `kind` variants also include an optional `toolCallId` linking back to the tool call that triggered the request. +Write requests can also include `fileEdits` in both `permissionRequest` and `promptRequest`. Each entry contains an optional `before` and `after` snapshot, each with an absolute `path` in the session filesystem namespace and complete UTF-8 `content`. A missing `before` means creation; a missing `after` means deletion. An empty `content` string represents an empty file, not an unavailable preview. A move can have different paths on its two sides. When a move overwrites an existing destination, separate entries describe the source deletion and destination replacement. + +These snapshots describe the planned operation, not a later read of the live filesystem. The runtime omits `fileEdits` when it cannot provide a complete text preview, including requests made before reading a sandbox-protected file, non-UTF-8 contents, or an unreadable or non-regular move destination, such as a named pipe. Do not infer a deletion from an empty legacy `newFileContents` value. The existing fields and approval choices remain available to consumers that do not use previews. + ### `permission.completed` A permission request was resolved. @@ -856,7 +860,7 @@ A skill was activated for the current conversation. | `name` | `string` | ✅ | Skill name | | `path` | `string` | ✅ | File path to the SKILL.md definition | | `content` | `string` | ✅ | Full skill content injected into the conversation | -| `allowedTools` | `string[]` | | Tools auto-approved while this skill is active | +| `allowedTools` | `string[]` | | Tools listed in the skill's `allowed-tools` frontmatter. The SDK doesn't approve them automatically; your permission handler still decides. The Copilot CLI auto-approves them while the skill is active. | | `pluginName` | `string` | | Plugin the skill originated from | | `pluginVersion` | `string` | | Plugin version | diff --git a/docs/features/usage-and-billing.md b/docs/features/usage-and-billing.md index ec662b6850..c412cb35c2 100644 --- a/docs/features/usage-and-billing.md +++ b/docs/features/usage-and-billing.md @@ -22,9 +22,21 @@ The table below maps each signal to the API that exposes it. | Accumulated AI credit and token totals | `session.usage.getMetrics` | Session | RPC | | Per-model AI credit pricing | `models.list` | Server | RPC | | Account quota and premium interactions | `account.getQuota` | Server | RPC | +| Session-owned provider quota observations | `session.quota.get` and `session.quota.refresh` | Session | RPC | +| Provider admission-state updates | `session.quota_observation` | Session | Event | + +`session.quota.get` reads local runtime state; `session.quota.refresh` refreshes the provider catalogs and quota sources. Both return `providerQuotas`, keyed by provider identity, quota ID, and observation kind. The runtime keeps one observation store. The legacy `snapshots` field is a derived compatibility view of authoritative budgets, not a second source of quota state. + +Provider cardinality is an emergent property of actual usage and observations supplied to the seam. This API neither knows nor enforces how many providers a user may use: it records and projects zero, one, or many entries identically. Producers supply stable provider/account-scoped references; usage adds model identity, and quota adds quota identity and observation kind. `get()` returns the full known collection, so callers can select an exact key, a subset, or all entries without provider-specific methods. Acquisition uses the sources supplied by the upstream account/model layer; it does not manufacture a union or impose a selected-provider filter on reads. + +Check `observationKind`, `quantityKind`, and `acquisitionStatus` before interpreting a reading. An `authoritative_budget` can supply progress and reset metadata. An `advisory_balance` reports independent signed 64-bit quantities without promising a percentage, reset window, or post-call balance. An `admission_state` reports permission/capacity at request admission and carries no quantities; it does not replace an account balance. Preserve missing values and explicit nulls rather than converting them to zero. A failed or unavailable acquisition is not quota exhaustion. + +For Microsoft 365 Copilot, access and capacity are service verdicts, while quantities are advisory. For example, `allowed`/`available` with both quantities explicitly zero means **0 / 0 AIC reported**, not 100% consumed or inconsistent state. A missing entitlement is different from a zero entitlement. The `-1` entitlement sentinel means unlimited entitlement without changing the reported capacity state. Inference headers can reflect cached admission state; neither those headers nor an on-demand quota refresh establish the charge for the preceding call. + +Usage totals belong to a session, not the active account. In the CLI, switching away from a non-empty Microsoft 365 Copilot session requires starting a new session. The previous session retains its usage and history for resume; the new session starts its own totals. > [!NOTE] -> `session.usage.getMetrics`, `session.metadata.contextInfo`, and `session.metadata.recomputeContextTokens` are marked experimental in the generated RPC surface. In .NET they raise the `GHCP001` experimental diagnostic, which you suppress with `#pragma warning disable GHCP001` or a project-level `GHCP001`. Pin both the SDK and the Copilot CLI runtime if your application depends on them. +> `session.quota`, `session.usage.getMetrics`, `session.metadata.contextInfo`, and `session.metadata.recomputeContextTokens` are marked experimental in the generated RPC surface. In .NET they raise the `GHCP001` experimental diagnostic, which you suppress with `#pragma warning disable GHCP001` or a project-level `GHCP001`. Pin both the SDK and the Copilot CLI runtime if your application depends on them. The field tables below list only the fields used in the examples on this page. The complete, always-current field reference is the generated SDK types plus [Streaming events](./streaming-events.md), which is regenerated from the CLI schema on every dependency bump. Treat those as the source of truth and this page as a task-oriented guide. diff --git a/docs/runtime-supervised-host.md b/docs/runtime-supervised-host.md index 427fe39daf..c0999bddbb 100644 --- a/docs/runtime-supervised-host.md +++ b/docs/runtime-supervised-host.md @@ -106,14 +106,23 @@ Startup fails if a requested transport cannot become ready, rather than silently downgrading to local-only hosting. Select transports at startup; dispose and recreate the host to change them. +`githubEnvironment.requireConnectionBinding` defaults to `true`: sealed +authentication must bind the current handshake challenge, a fresh nonce and +timestamp. Explicit `false` selects compatibility with clients sending unbound +encrypted tokens. Relay encryption and resource authorization stay mandatory, +but an unbound sealed token is replayable. This is the same transitional policy +supported by `copilotd`, not a switch to plaintext authentication. + GitHub-only hosting does not open a local listener. Its host handle has an environment ID but no local URL or connection token. `environmentId` is absent for local-only hosting. Disposal ends transport and registration activity without deleting the saved MC environment record or application-owned sessions. Registering an environment does not publish every application session. Use -`publishSession` for existing resident sessions; factory callbacks and durable -catalog behavior are unchanged. Environment management is independent of a +`publishSession` for an existing resident session, and `listSessions` to read +the host's complete advertised catalog of live and dormant sessions. Listing +does not start a host, publish a session, or paginate results. Factory callbacks +and durable catalog behavior are unchanged. Environment management is independent of a running host and available only through generated `rpc.environments.list`, `rpc.environments.get`, and `rpc.environments.delete` operations, using each language's naming conventions. @@ -378,7 +387,8 @@ configuration before calling these methods, just as in the creation examples. Python and .NET handles support asynchronous context management; Java handles support try-with-resources. Go callers explicitly invoke `Dispose(ctx)`. -Only durable catalog entries marked as application-owned invoke the resume +Durable catalog entries marked as application-owned, including published +application sessions, invoke the resume factory. If its resume callback is missing, restoration fails rather than silently falling back to host-owned creation. Published resident sessions attach directly and do not invoke either factory. This callback does not provide arbitrary adoption or reconfiguration @@ -398,11 +408,33 @@ and `sessionUri`. Publication does not call the factory, copy history, replace the native session, or transfer ownership. Its metadata and workspace come from the resident session, not from an application-supplied configuration. -Published sessions are discoverable only for this listener's lifetime. They -are not imported into its durable catalog. Stopping the listener detaches its -participation without deleting the original session or transcript. A missing -or replaced resident session cannot be silently restored from disk by the -listener. +Publication records the session in the durable, compute-scoped host catalog. +Stopping the listener detaches its participation without deleting the catalog +entry, original session, or transcript. A later host using the same compute +identity can discover it as a dormant session. Restoring an application-owned +session requires the owning application's `resumeSession` callback to configure +its tools, hooks, and handlers; the host does not silently substitute host-owned +session construction. A currently attached resident session still attaches +directly without invoking a factory. The SDK does not expose an unpublish operation. + +### Listing host sessions + +Call the owner-bound host handle to read every live or dormant session currently +advertised by its host. The runtime returns the complete catalog in one response; +the method does not start a host or publish sessions. The host ID is supplied +by the handle, so the call stays on the original owning connection. +Each method returns a `HostListSessionsResult` with a `sessions` collection, +not the collection directly. In Node.js, use +`const { sessions } = await host.listSessions()`. + +| SDK | Method | +| --- | --- | +| Node.js | `host.listSessions()` | +| Python | `await host.list_sessions()` | +| Go | `host.ListSessions(ctx)` | +| .NET | `host.ListSessionsAsync(cancellationToken)` | +| Java | `host.listSessions()` | +| Rust | `host.list_sessions().await` | ### CLI hosting commands @@ -417,14 +449,11 @@ Sharing also shows the session URI. Use an AHP 0.9 client with the connection token and ordinary GitHub resource authentication; the connection token alone does not bypass resource authorization. -`/ahp status` shows connection information. `/ahp stop` stops the **entire -listener and all its shares**. `/remote unshare` removes the foreground session. -The pinned host has no per-session unregister operation, so unsharing drains -and restarts the listener at the same endpoint with the same connection token -before republishing other shares. Other clients must reconnect; local sessions -and their identities remain unchanged. Exiting the owning CLI stops the -listener as well. There is one listener per CLI/effective catalog, not one -listener per shared session. +`/ahp status` shows connection information. `/ahp stop` stops the entire +listener and its active participation, not its durable catalog. Other clients +must reconnect after hosting restarts; local sessions and their identities +remain unchanged. Exiting the owning CLI stops the listener as well. Hosting +lifetime is separate from durable publication. `--ahp-host [--listen host:port] [--workspace directory]` serves this same backend in the CLI process, using normal SDK session construction, managed policy, @@ -440,19 +469,36 @@ Outbound relay, host-picker and explicitly configured external-daemon controls r ## Durable catalog and single host owner -The runtime passes its actual resolved data directory to the host library; the single AHP -catalog lives at `/ahp/sessions`. It follows the same +The runtime passes its actual resolved data directory and compute identity to +the host library. Durable catalogs are scoped to both the effective Copilot +home and compute identity. The effective home follows the same default `~/.copilot`, `COPILOT_HOME`, and SDK `baseDirectory` resolution as that -runtime. The catalog contains sessions previously created through AHP, not all -SDK/CLI sessions. Listener disposal, owner disconnect, and restart retain it. +runtime. Each catalog contains sessions previously created through AHP and +explicitly published resident sessions, not all SDK/CLI sessions. +Listener disposal, owner disconnect, and restart retain it. A replacement listener can list and resume these sessions after authenticating. +Supply top-level `AhpHostOptions.computeId` to keep the same catalog when switching +between local and Mission Control hosting. If omitted for a local-only start, +the runtime persists a stable identity in its settings; the SDK never generates +one. Mission Control's `githubEnvironment.computeId` remains required. When both +compute IDs are supplied, they must agree or startup fails. + +| SDK | Top-level compute identity | +| --- | --- | +| Node.js | `computeId` | +| Python | `compute_id` | +| Go | `ComputeID` | +| .NET | `ComputeId` | +| Java | `setComputeId(...)` | +| Rust | `with_compute_id(...)` | + Only one AHP server may own a catalog at a time. A second start for the -same location fails, including from another runtime. Ordinary runtimes, SDK +same home and compute identity fails, including from another runtime. Ordinary runtimes, SDK clients, and sessions do not acquire this lock and remain usable. The lock is kernel-managed, non-blocking, held until shutdown writes finish, and released -even after forced process termination. Different effective homes have separate -catalogs. This does not change standalone `copilotd` defaults or concurrency +even after forced process termination. Different effective homes or compute +identities have separate catalogs. This does not change standalone `copilotd` defaults or concurrency behavior, and does not add standalone/in-process shared-writer support. ## Current GHES shell limitation diff --git a/docs/setup/multi-tenancy.md b/docs/setup/multi-tenancy.md index ebbafe4fb0..7fe893a070 100644 --- a/docs/setup/multi-tenancy.md +++ b/docs/setup/multi-tenancy.md @@ -334,6 +334,24 @@ const client = new CopilotClient({ 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. +Runtime-owned durable permission choices also use the session filesystem. Under the provider's `sessionStatePath`, `permissions.json` retains its top-level `locations` map with `tool_approvals` and `allowed_directories`; `settings.json` stores top-level `allowedUrls` and `sandbox`; and `config.json` stores top-level `trustedFolders`. + +URL approvals are read only from `settings.json`; legacy user-setting fields such as `allowedUrls` in `config.json` are ignored, matching host behavior. + +Location keys are normalized provider directory paths, with no added prefix. Resolution follows the provider's path conventions without inspecting the host filesystem or discovering host Git repositories. `/workspace` and `/workspace/sub` select different location entries. + +The runtime does not add session-ID partitions to these files or change their sharing granularity. Sessions accessing the same files in the same provider namespace share remembered grants. Your application must use distinct namespaces for tenants or sessions that require isolation, authorize access to each namespace, and reconnect resumed sessions to their original namespace. + +With a separate namespace per session, permanent grants survive that session's resumes rather than becoming tenant-wide grants for new sessions. Sharing grants across sessions requires sharing the consent files while keeping other session state separate. The runtime serializes consent updates only within the same provider endpoint and process; applications that share backing files across endpoints or processes must coordinate concurrent updates. + +The runtime blocks direct provider-backed file writes to the lexical approval-metadata paths as defense in depth, not as a tamper-proof storage boundary. Providers must not expose writable aliases (such as symlinks or Windows 8.3 short names) to approval metadata through agent file tools. Shell tools do not run through SessionFS, and their commands are not checked against its virtual metadata paths. If your application separately exposes the provider's backing storage to shell execution or other arbitrary code, your host must protect that storage. + +Session filesystem approval operations never import or fall back to remembered permissions from the host's `permissions-config.json`, URL or sandbox settings from `settings.json`, or folder trust from `config.json`. They do not update those host files, even when the provider has no approvals or reports an error. A provider error is not permission to use host consent. URL deny rules remain authoritative, and folder trust uses provider paths without host Git discovery. + +Approve-once, approve-for-session, rejections, and session policy changes retain their existing lifetimes and event-replay behavior. Storage routing does not turn them into new permanent grants. Protect session transcripts, including durable permission events, with the same tenant isolation as approval metadata. + +This boundary applies only to sessions using a session filesystem provider. All SDK applications without `sessionFs`, in both `empty` and `copilot-cli` modes, and ordinary CLI sessions retain existing host-backed persistence for remembered locations, permanent URL approvals, folder trust, and sandbox settings. + Verified public SDK surfaces: | Language | Client-level config | Per-session provider | diff --git a/dotnet/README.md b/dotnet/README.md index 6bde71b71c..84f5b650f1 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -44,6 +44,12 @@ For GitHub Mission Control, set instead, or configure both transports. GitHub environment name and compute ID are required; there is no implicit local listener. The host's `Url`, `Token`, and `Pid` are nullable; `EnvironmentId` contains the GitHub environment ID when configured. +Call `host.ListSessionsAsync()` to read the complete advertised catalog of live +and dormant sessions. +Set top-level `ComputeId` to reuse the durable catalog across local and Mission +Control hosting; it must agree with `GitHubEnvironment.ComputeId` when both are +supplied. The runtime persists an omitted local-only identity. Publication +survives host shutdown; dormant application sessions require your resume callback. Environment list/get/delete operations are available only through the generated RPC API. See [runtime-supervised AHP hosting](../docs/runtime-supervised-host.md) for creation and resume callbacks, resident-session publication, ownership, and shared-snapshot E2Es. @@ -178,6 +184,9 @@ Start the CLI server and establish connection. ##### `StopAsync(): Task` Stop the server and close all sessions. Throws if errors are encountered during cleanup. +Closing a session stops subscribed event delivery, drops queued events, and releases +subscriptions without waiting for handlers already admitted for dispatch. Pending `SendAndWaitAsync` +operations fail with `IOException` if the session closes before their final response arrives. For an owned stdio runtime, graceful shutdown closes stdin and waits up to 10 seconds for host cleanup, including telemetry export. This cleanup is best-effort: if the wait times out, the process is terminated and that timeout alone is not reported as a cleanup @@ -186,6 +195,20 @@ error. A successful return does not guarantee that all telemetry was exported. ##### `ForceStopAsync(): Task` Force stop the CLI server without graceful cleanup. Use when `StopAsync()` takes too long. +Stops session event dispatch and releases queued events and subscriptions. A handler already +admitted for dispatch may finish; shutdown does not wait for it. Pending `SendAndWaitAsync` operations fail +with `IOException` if the session closes before their final response arrives. +The SDK releases its references to later handlers' captured objects even if an admitted handler remains blocked. +Local retirement also releases tool, command, hook, auth/input, provider, canvas, +and transform registrations, without changing caller-owned configuration or joining +callbacks already admitted. Registration and callback lookup share a retirement fence; +late accepted tool replacements cannot restore handlers. Ordinary disposal retains +hook callbacks through the detach response and performs local retirement in `finally`. +Both stop methods close session admission before taking the session snapshot. Concurrent +create/resume setup on that connection is rejected and retired locally; restarting the +client opens admission only for the new connection. +Cleanup of a rejected cloud creation stays on its original connection and cannot +restart the client during shutdown. ##### `CreateSessionAsync(SessionConfig? config = null): Task` @@ -207,6 +230,7 @@ Create a new conversation session. - `WorkingDirectory` - Working directory for the session. When not set, the runtime uses its own process working directory. - `EnableSessionStore` - Enables the cross-session store for search and retrieval across sessions. When unset in `CopilotClientMode.CopilotCli`, the runtime default applies (enabled). In `CopilotClientMode.Empty`, defaults to disabled. - `GitHubTokenProvider` - Acquires session-scoped GitHub tokens on demand. Return `GitHubTokenProviderResult.FromToken` with a positive `ExpiresIn` value (production GitHub tokens typically use `8 * 60 * 60` seconds), or `GitHubTokenProviderResult.Cancel()`. Cannot be combined with `GitHubToken`. +- `SkillProvider` - Experimental session-scoped skill provider. See [Skill providers (experimental)](#skill-providers-experimental). - `OnPermissionRequest` - Optional handler called before each tool execution to approve or deny it. When omitted, permission requests are emitted as events and left pending for manual resolution. `PermissionHandler.ApproveAll` approves requests when managed settings are disabled and throws when `EnableManagedSettings` is true. Custom handlers can inspect `ManagedApprovalRequired` for human-facing confirmation logic. See [Permission Handling](#permission-handling) section. - `OnUserInputRequest` - Handler for legacy question-and-answer requests from the agent. Enables the legacy `ask_user` tool. See [User Input Requests](#user-input-requests) section. - `AskUserVariant` - Selects the model-facing `ask_user` tool shape. Defaults to `AskUserVariant.Legacy`; use `AskUserVariant.Elicitation` with `OnElicitationRequest`. @@ -225,6 +249,7 @@ Resume an existing session. Returns the session with `WorkspacePath` populated i - `OnPermissionRequest` - Optional handler called before each tool execution to approve or deny it. See [Permission Handling](#permission-handling) section. - `GitHubTokenProvider` - Replaces the session-scoped token provider when resuming. Cannot be combined with `GitHubToken`. +- `SkillProvider` - Re-supplies the session-scoped skill provider when resuming. - `AskUserVariant` - Re-supplies the model-facing `ask_user` tool shape on cold resume. - `AllowTranscriptRecovery` - Repairs a damaged transcript when true. The default is true in all modes; set false to reject recovery. `session.TranscriptRecovery` contains @@ -254,6 +279,62 @@ await using var session = await client.CreateSessionAsync(new SessionConfig Initial acquisition runs during session creation or resume. Cancellation, provider errors, and invalid token responses reject that operation instead of falling back to ambient authentication. Idle sessions refresh only before their next credential-consuming operation; there is no background refresh timer. +##### Skill providers (experimental) + +Set `SessionConfig.SkillProvider` or `ResumeSessionConfig.SkillProvider` to +serve session-scoped skills from your application. The provider is not persisted: +pass it again on every resume, because resuming without one unbinds it. Skill +providers are only supported for local sessions; `CreateSessionAsync` throws if +`Cloud` and `SkillProvider` are both set. The skill provider types are +experimental and raise the `GHCP001` diagnostic; suppress it with +`#pragma warning disable GHCP001` or `GHCP001`. + +```csharp +#pragma warning disable GHCP001 // Skill providers are experimental. + +public sealed class MySkillProvider : ISkillProvider +{ + public Task> ListSkillsAsync(CancellationToken cancellationToken) => + Task.FromResult>( + [ + new() + { + Name = "project-facts", + Description = "Important facts about this host application", + ArgumentHint = "" + } + ]); + + public Task ReadSkillAsync(string name, CancellationToken cancellationToken) => + Task.FromResult(name == "project-facts" + ? """ + # Project facts + + Use the application's project index before answering. + """ + : null); +} + +await using var client = new CopilotClient(new CopilotClientOptions +{ + Mode = CopilotClientMode.Empty +}); + +await using var session = await client.CreateSessionAsync(new SessionConfig +{ + AvailableTools = [], // Empty mode requires an explicit tool allow-list. + SkillProvider = new MySkillProvider(), + EnableSkills = true // Required in empty mode; otherwise skills default off. +}); +``` + +The runtime may call `ListSkillsAsync` and `ReadSkillAsync` concurrently. Honor +the supplied cancellation token; it is canceled when the runtime abandons the +request (for example, on timeout, session disposal, or a resume that replaces the +provider) or the connection closes. Return `null` from `ReadSkillAsync` when a +skill name is not found. Optional `SkillProviderDescriptor` properties are +omitted from JSON when unset. + ##### `PingAsync(string? message = null): Task` Ping the server to check connectivity. @@ -542,6 +623,24 @@ await session2.DisposeAsync(); --- +## Provider-qualified model selection + +Use the experimental request-object overload to select the `modelId` and `providerId` from a model catalog entry: + +```csharp +using GitHub.Copilot.Rpc; + +#pragma warning disable GHCP001 // Provider-qualified model selection is experimental. +await session.Rpc.Model.SwitchToAsync(new ModelSwitchToRequest +{ + ModelId = modelId, + ProviderId = providerId, +}); +#pragma warning restore GHCP001 +``` + +The SDK supplies the session ID. Existing positional calls, including `session.Rpc.Model.SwitchToAsync("auto", AutoTier.Balance)`, retain their original parameter order and defaults. + ## Auto routing tiers The canonical values are `AutoTier.Efficiency`, `AutoTier.Balance`, `AutoTier.Intelligence`, and `AutoTier.Fast`, which send `efficiency`, `balance`, `intelligence`, and `fast` on the wire. Fast is an integrator-only latency preset, not a fourth first-party GitHub Copilot preference. The SDK forwards the requested value without deciding eligibility or inspecting client identity. An externally supplied older runtime returns its native runtime or JSON-RPC error; the SDK does not downgrade or silently ignore the request. diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index 999440992f..77df3cba7f 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -71,6 +71,8 @@ public sealed partial class CopilotClient : IDisposable, IAsyncDisposable /// that has not been explicitly disposed or removed. /// internal readonly ConcurrentDictionary _sessions = new(); + private readonly object _sessionAdmissionLock = new(); + private bool _sessionAdmissionClosed; private readonly ConcurrentDictionary>> _gitHubTokenProviders = new(); private readonly CopilotClientOptions _options; @@ -365,7 +367,14 @@ private static bool IsFullyQualifiedPath(string path) /// public Task StartAsync(CancellationToken cancellationToken = default) { - return _connectionTask ??= StartCoreAsync(cancellationToken); + lock (_sessionAdmissionLock) + { + if (_connectionTask is null) + { + _sessionAdmissionClosed = false; + } + return _connectionTask ??= StartCoreAsync(cancellationToken); + } async Task StartCoreAsync(CancellationToken ct) { @@ -394,29 +403,7 @@ async Task StartCoreAsync(CancellationToken ct) ffiEnvironment["COPILOT_DISABLE_KEYTAR"] = "1"; } - var ffiArgs = new List(); - if (_options.LogLevel is { } logLevel && !string.IsNullOrEmpty(logLevel.Value)) - { - ffiArgs.AddRange(["--log-level", logLevel.Value]); - } - if (!string.IsNullOrEmpty(_options.GitHubToken)) - { - ffiArgs.AddRange(["--auth-token-env", "COPILOT_SDK_AUTH_TOKEN"]); - } - var useLoggedInUser = _options.UseLoggedInUser ?? string.IsNullOrEmpty(_options.GitHubToken); - if (!useLoggedInUser) - { - ffiArgs.Add("--no-auto-login"); - } - if (_options.SessionIdleTimeoutSeconds is > 0) - { - ffiArgs.AddRange(["--session-idle-timeout", _options.SessionIdleTimeoutSeconds.Value.ToString(CultureInfo.InvariantCulture)]); - } - if (_options.EnableRemoteSessions) - { - ffiArgs.Add("--remote"); - } - + var ffiArgs = BuildInProcessRuntimeArguments(_options); var explicitCliPath = System.Environment.GetEnvironmentVariable("COPILOT_CLI_PATH"); if (string.IsNullOrEmpty(explicitCliPath)) { @@ -556,11 +543,12 @@ await InvokeRpcAsync( /// public async Task StopAsync() { + var sessions = CloseSessionAdmission(clearSessions: false); DisconnectAhpHosts(); List errors = []; - CancelPendingExternalTools(); + CancelPendingExternalTools(sessions); - foreach (var session in _sessions.Values.ToArray()) + foreach (var session in sessions) { try { @@ -572,7 +560,6 @@ public async Task StopAsync() } } - _sessions.Clear(); ClearGitHubTokenProviders(); await CleanupConnectionAsync(errors, gracefulRuntimeShutdown: true); @@ -588,6 +575,7 @@ public async Task StopAsync() /// Use this when fails or takes too long. This method: /// /// Clears all sessions immediately without destroying them + /// Stops session event delivery without waiting for running handlers /// Force closes the connection /// Kills the CLI process (if spawned by this client) /// @@ -604,9 +592,13 @@ public async Task StopAsync() /// public async Task ForceStopAsync() { + var sessions = CloseSessionAdmission(clearSessions: true); DisconnectAhpHosts(); - CancelPendingExternalTools(); - _sessions.Clear(); + CancelPendingExternalTools(sessions); + foreach (var session in sessions) + { + session.Retire(); + } ClearGitHubTokenProviders(); var errors = new List(); @@ -614,6 +606,20 @@ public async Task ForceStopAsync() ThrowErrors(errors); } + private CopilotSession[] CloseSessionAdmission(bool clearSessions) + { + lock (_sessionAdmissionLock) + { + _sessionAdmissionClosed = true; + var sessions = _sessions.Values.ToArray(); + if (clearSessions) + { + _sessions.Clear(); + } + return sessions; + } + } + private static void ThrowErrors(List? errors) { if (errors is not null) @@ -632,14 +638,17 @@ private static void ThrowErrors(List? errors) private async Task CleanupConnectionAsync(List? errors, bool gracefulRuntimeShutdown) { - var connectionTask = _connectionTask; + Task? connectionTask; + lock (_sessionAdmissionLock) + { + connectionTask = _connectionTask; + _connectionTask = null; + } if (connectionTask is null) { return; } - _connectionTask = null; - Connection ctx; try { @@ -892,6 +901,7 @@ private CopilotSession InitializeSession( session.RegisterElicitationHandler(config.OnElicitationRequest); session.RegisterExitPlanModeHandler(config.OnExitPlanModeRequest); session.RegisterAutoModeSwitchHandler(config.OnAutoModeSwitchRequest); + session.RegisterSkillProvider(config.SkillProvider); if (config.OnUserInputRequest != null) { session.RegisterUserInputHandler(config.OnUserInputRequest); @@ -911,7 +921,7 @@ private CopilotSession InitializeSession( ConfigureSessionFsHandlers(session, config.CreateSessionFsProvider); session.SetCanvasHandler(config.CanvasHandler); session.RegisterBearerTokenProviders(BuildBearerTokenCallbacks(config)); - RegisterSession(session); + RegisterSession(session, rpc); session.StartProcessingEvents(); LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null, callerName + " local setup complete. Elapsed={Elapsed}, SessionId={SessionId}, Tools={ToolsCount}, Commands={CommandsCount}, Hooks={HasHooks}", @@ -1190,6 +1200,10 @@ public async Task CreateSessionAsync(SessionConfig config, Cance { ArgumentNullException.ThrowIfNull(config); ValidateGitHubTokenConfig(config); + if (config.Cloud is not null && config.SkillProvider is not null) + { + throw new ArgumentException("Skill providers are not supported for cloud sessions."); + } var connection = await EnsureConnectedAsync(cancellationToken); var totalTimestamp = Stopwatch.GetTimestamp(); @@ -1248,6 +1262,7 @@ public async Task CreateSessionAsync(SessionConfig config, Cance var request = new CreateSessionRequest( config.Model, localSessionId, + config.Name, config.ClientName, config.ReasoningEffort, config.ReasoningSummary, @@ -1307,10 +1322,13 @@ public async Task CreateSessionAsync(SessionConfig config, Cance Cloud: config.Cloud, RefreshCustomInstructions: config.RefreshCustomInstructions, InstructionDirectories: config.InstructionDirectories, + AgentDirectories: config.AgentDirectories, + HookDirectories: config.HookDirectories, PluginDirectories: config.PluginDirectories, DisabledMcpServers: config.DisabledMcpServers, LargeOutput: config.LargeOutput, ToolSearch: config.ToolSearch, + ImageGeneration: config.ImageGeneration, Memory: config.Memory, Canvases: config.Canvases, RequestCanvasRenderer: config.RequestCanvasRenderer, @@ -1324,10 +1342,12 @@ public async Task CreateSessionAsync(SessionConfig config, Cance FeatureFlags: config.FeatureFlags, ExpAssignments: config.ExpAssignments, EnableManagedSettings: config.EnableManagedSettings, + EnforceManagedModelDefaults: config.EnforceManagedModelDefaults, GitHubMcpToolConfig: config.GitHubMcpToolConfig, ManagedSettings: config.ManagedSettings, EnableGitHubTelemetryForwarding: _options.OnGitHubTelemetry != null ? true : null, - AdditionalDirectories: config.AdditionalDirectories); + AdditionalDirectories: config.AdditionalDirectories, + HasSkillProvider: config.SkillProvider is not null ? true : null); var rpcTimestamp = Stopwatch.GetTimestamp(); @@ -1401,7 +1421,13 @@ public async Task CreateSessionAsync(SessionConfig config, Cance try { using var cleanupTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - await DeleteSessionAsync(serverAssignedSessionId, cleanupTimeout.Token).ConfigureAwait(false); + var deletion = await InvokeRpcAsync( + connection.Rpc, "session.delete", [new DeleteSessionRequest(serverAssignedSessionId)], + cleanupTimeout.Token).ConfigureAwait(false); + if (!deletion.Success) + { + throw new InvalidOperationException($"Failed to delete session {serverAssignedSessionId}: {deletion.Error}"); + } } catch (Exception cleanupError) when (cleanupError is OperationCanceledException or IOException @@ -1571,10 +1597,13 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes RemoteSession: config.RemoteSession, ContinuePendingWork: config.ContinuePendingWork, InstructionDirectories: config.InstructionDirectories, + AgentDirectories: config.AgentDirectories, + HookDirectories: config.HookDirectories, PluginDirectories: config.PluginDirectories, DisabledMcpServers: config.DisabledMcpServers, LargeOutput: config.LargeOutput, ToolSearch: config.ToolSearch, + ImageGeneration: config.ImageGeneration, Memory: config.Memory, Canvases: config.Canvases, RequestCanvasRenderer: config.RequestCanvasRenderer, @@ -1589,11 +1618,13 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes FeatureFlags: config.FeatureFlags, ExpAssignments: config.ExpAssignments, EnableManagedSettings: config.EnableManagedSettings, + EnforceManagedModelDefaults: config.EnforceManagedModelDefaults, GitHubMcpToolConfig: config.GitHubMcpToolConfig, ManagedSettings: config.ManagedSettings, EnableGitHubTelemetryForwarding: _options.OnGitHubTelemetry != null ? true : null, AdditionalDirectories: config.AdditionalDirectories, - AllowTranscriptRecovery: config.AllowTranscriptRecovery); + AllowTranscriptRecovery: config.AllowTranscriptRecovery, + HasSkillProvider: config.SkillProvider is not null ? true : null); var rpcTimestamp = Stopwatch.GetTimestamp(); var response = await InvokeRpcAsync( @@ -1807,6 +1838,7 @@ public async Task DeleteSessionAsync(string sessionId, CancellationToken cancell if (_sessions.TryRemove(sessionId, out var session)) { + session.ClearSkillProvider(); session.ReleaseGitHubTokenProviderRegistration(); } } @@ -2225,7 +2257,7 @@ private void ConfigureSessionFsHandlers(CopilotSession session, Func envir return GetBundledNativePath(OperatingSystem.IsWindows() ? "copilot.exe" : "copilot", out searchedPath); } + private static List BuildInProcessRuntimeArguments(CopilotClientOptions options) + { + var args = new List(); + if (options.LogLevel is { } logLevel && !string.IsNullOrEmpty(logLevel.Value)) + { + args.AddRange(["--log-level", logLevel.Value]); + } + if (!string.IsNullOrEmpty(options.GitHubToken)) + { + args.AddRange(["--auth-token-env", "COPILOT_SDK_AUTH_TOKEN"]); + } + var useLoggedInUser = options.UseLoggedInUser ?? string.IsNullOrEmpty(options.GitHubToken); + if (!useLoggedInUser) + { + args.Add("--no-auto-login"); + } + if (options.SessionIdleTimeoutSeconds is > 0) + { + args.AddRange(["--session-idle-timeout", options.SessionIdleTimeoutSeconds.Value.ToString(CultureInfo.InvariantCulture)]); + } + if (options.EnableRemoteSessions) + { + args.Add("--remote"); + } + + var cliLoginSyncIntegrationId = + System.Environment.GetEnvironmentVariable("GITHUB_COPILOT_INTEGRATION_ID")?.Trim(); + if (!string.IsNullOrEmpty(cliLoginSyncIntegrationId)) + { + args.Add($"--cli-login-sync-integration-id={cliLoginSyncIntegrationId}"); + } + return args; + } + private static string? GetBundledNativePath(string binaryName, out string searchedPath) { // Always use portable RID (e.g., linux-x64) to match the build-time placement, @@ -2753,6 +2819,8 @@ private async Task ConnectToServerAsync(Process? cliProcess, string? rpc.SetLocalRpcMethod("autoModeSwitch.request", handler.OnAutoModeSwitchRequest); rpc.SetLocalRpcMethod("hooks.invoke", handler.OnHooksInvoke); rpc.SetLocalRpcMethod("systemMessage.transform", handler.OnSystemMessageTransform); + rpc.SetLocalRpcMethod("skillProvider.list", handler.OnSkillProviderList, singleObjectParam: true); + rpc.SetLocalRpcMethod("skillProvider.read", handler.OnSkillProviderRead, singleObjectParam: true); ClientSessionApiRegistration.RegisterClientSessionApiHandlers(rpc, sessionId => { var session = GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}"); @@ -2856,14 +2924,15 @@ private async Task CancelExternalToolsWhenConnectionClosesAsync(JsonRpc rpc) CancelPendingExternalTools(); } - private void CancelPendingExternalTools() + private void CancelPendingExternalTools(IEnumerable? sessions = null) { if (_clientGlobalApis?.LlmInference is LlmInferenceAdapter llmInferenceAdapter) { llmInferenceAdapter.CancelPending(); } - foreach (var session in _sessions.Values) + foreach (var session in sessions ?? _sessions.Values) { + session.ClearSkillProvider(); session.CancelPendingExternalTools(); } } @@ -2911,12 +2980,29 @@ private static JsonSerializerOptions CreateSerializerOptions() return session; } - private void RegisterSession(CopilotSession session) + private void RegisterSession(CopilotSession session, JsonRpc rpc) { - if (!_sessions.TryAdd(session.SessionId, session)) + Exception error; + lock (_sessionAdmissionLock) { - throw new InvalidOperationException($"Session '{session.SessionId}' is already tracked by this client."); + // A restarted connection must not admit setup that began on the stopped transport. + if (!_sessionAdmissionClosed + && _connectionTask?.Status == System.Threading.Tasks.TaskStatus.RanToCompletion + && ReferenceEquals(_connectionTask.Result.Rpc, rpc)) + { + if (_sessions.TryAdd(session.SessionId, session)) + { + return; + } + error = new InvalidOperationException($"Session '{session.SessionId}' is already tracked by this client."); + } + else + { + error = new IOException("Cannot register a session on a stopped connection."); + } } + session.Retire(); + throw error; } /// @@ -3039,6 +3125,32 @@ public async ValueTask OnSystemMessageTransfo return await session.HandleSystemMessageTransformAsync(sections); } + public async ValueTask OnSkillProviderList(SkillProviderListRequest request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + if (string.IsNullOrEmpty(request.SessionId)) + { + throw new ArgumentException("Skill provider list request is missing a session id."); + } + + var session = client.GetSession(request.SessionId) + ?? throw new InvalidOperationException($"No skill provider for session: {request.SessionId}"); + return await session.HandleSkillProviderListAsync(cancellationToken); + } + + public async ValueTask OnSkillProviderRead(SkillProviderReadRequest request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + if (string.IsNullOrEmpty(request.SessionId) || string.IsNullOrEmpty(request.Name)) + { + throw new ArgumentException("Skill provider read request is missing a session id or skill name."); + } + + var session = client.GetSession(request.SessionId) + ?? throw new InvalidOperationException($"No skill provider for session: {request.SessionId}"); + return await session.HandleSkillProviderReadAsync(request.Name, cancellationToken); + } + } private class Connection( @@ -3117,6 +3229,7 @@ public static string Escape(string arg) internal record CreateSessionRequest( string? Model, string? SessionId, + string? Name, string? ClientName, string? ReasoningEffort, ReasoningSummary? ReasoningSummary, @@ -3176,10 +3289,13 @@ internal record CreateSessionRequest( CloudSessionOptions? Cloud = null, bool? RefreshCustomInstructions = null, IList? InstructionDirectories = null, + IList? AgentDirectories = null, + IList? HookDirectories = null, IList? PluginDirectories = null, [property: JsonPropertyName("disabledMcpServers")] IList? DisabledMcpServers = null, LargeToolOutputConfig? LargeOutput = null, ToolSearchConfig? ToolSearch = null, + ImageGenerationConfig? ImageGeneration = null, MemoryConfiguration? Memory = null, #pragma warning disable GHCP001 IList? Canvases = null, @@ -3194,10 +3310,12 @@ internal record CreateSessionRequest( [property: JsonPropertyName("featureFlags")] IDictionary? FeatureFlags = null, [property: JsonPropertyName("expAssignments")] CopilotExpAssignmentResponse? ExpAssignments = null, [property: JsonPropertyName("enableManagedSettings")] bool? EnableManagedSettings = null, + [property: JsonPropertyName("enforceManagedModelDefaults")] bool? EnforceManagedModelDefaults = null, [property: JsonPropertyName("managedSettings")] ManagedSettings? ManagedSettings = null, bool? EnableGitHubTelemetryForwarding = null, [property: JsonPropertyName("githubMcpToolConfig")] GitHubMcpToolConfig? GitHubMcpToolConfig = null, - IList? AdditionalDirectories = null); + IList? AdditionalDirectories = null, + bool? HasSkillProvider = null); #pragma warning restore GHCP001 internal record ToolDefinition( @@ -3296,10 +3414,13 @@ internal record ResumeSessionRequest( RemoteSessionMode? RemoteSession = null, bool? ContinuePendingWork = null, IList? InstructionDirectories = null, + IList? AgentDirectories = null, + IList? HookDirectories = null, IList? PluginDirectories = null, [property: JsonPropertyName("disabledMcpServers")] IList? DisabledMcpServers = null, LargeToolOutputConfig? LargeOutput = null, ToolSearchConfig? ToolSearch = null, + ImageGenerationConfig? ImageGeneration = null, MemoryConfiguration? Memory = null, #pragma warning disable GHCP001 IList? Canvases = null, @@ -3315,11 +3436,13 @@ internal record ResumeSessionRequest( [property: JsonPropertyName("featureFlags")] IDictionary? FeatureFlags = null, [property: JsonPropertyName("expAssignments")] CopilotExpAssignmentResponse? ExpAssignments = null, [property: JsonPropertyName("enableManagedSettings")] bool? EnableManagedSettings = null, + [property: JsonPropertyName("enforceManagedModelDefaults")] bool? EnforceManagedModelDefaults = null, [property: JsonPropertyName("managedSettings")] ManagedSettings? ManagedSettings = null, bool? EnableGitHubTelemetryForwarding = null, [property: JsonPropertyName("githubMcpToolConfig")] GitHubMcpToolConfig? GitHubMcpToolConfig = null, IList? AdditionalDirectories = null, - bool? AllowTranscriptRecovery = null); + bool? AllowTranscriptRecovery = null, + bool? HasSkillProvider = null); #pragma warning restore GHCP001 internal record ResumeSessionResponse( @@ -3407,6 +3530,21 @@ internal record UserInputRequestResponse( string Answer, bool WasFreeform); + internal record SkillProviderListRequest( + string SessionId); + +#pragma warning disable GHCP001 + internal record SkillProviderListResult( + IReadOnlyList Skills); +#pragma warning restore GHCP001 + + internal record SkillProviderReadRequest( + string SessionId, + string Name); + + internal record SkillProviderReadResult( + [property: JsonIgnore(Condition = JsonIgnoreCondition.Never)] string? Markdown); + internal record AutoModeSwitchRequestResponse( AutoModeSwitchResponse Response); @@ -3435,6 +3573,12 @@ internal record HooksInvokeResponse( [JsonSerializable(typeof(ExitPlanModeResult))] [JsonSerializable(typeof(GetLastSessionIdResponse))] [JsonSerializable(typeof(HooksInvokeResponse))] + [JsonSerializable(typeof(SkillProviderListRequest))] +#pragma warning disable GHCP001 + [JsonSerializable(typeof(SkillProviderListResult))] +#pragma warning restore GHCP001 + [JsonSerializable(typeof(SkillProviderReadRequest))] + [JsonSerializable(typeof(SkillProviderReadResult))] [JsonSerializable(typeof(ListSessionsRequest))] [JsonSerializable(typeof(ListSessionsResponse))] [JsonSerializable(typeof(GetSessionMetadataRequest))] diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index 080abf0116..abd757747b 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -107,2168 +107,2383 @@ internal sealed class ConnectRequest public string? Token { get; set; } } -/// Hosting capabilities and session capacity advertised by an environment. +/// The user's sandbox settings raised to the managed floor. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentCapabilities +internal sealed class SandboxResolveFlooredConfigResult { - /// Advertised Agent Host Protocol version. - [JsonPropertyName("ahpVersion")] - public string? AhpVersion { get; set; } - - /// Current session count, when advertised. - [JsonPropertyName("currentSessions")] - public long? CurrentSessions { get; set; } - - /// Feature identifiers advertised by the environment. - [JsonPropertyName("features")] - public IList Features { get => field ??= []; set; } - - /// Maximum session capacity, when advertised. - [JsonPropertyName("maxSessions")] - public long? MaxSessions { get; set; } + /// The floored sandbox config, normalized through the declared sandbox shape so only declared fields in a fixed order are present. + [JsonPropertyName("sandboxJson")] + public JsonElement SandboxJson { get; set; } } -/// Safe discovery information. Host-side relay bootstrap credentials are never included. +/// The user's sandbox settings and the managed sandbox floor to raise them to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubEnvironment +internal sealed class SandboxResolveFlooredConfigParams { - /// Hosting capabilities advertised by the environment. - [JsonPropertyName("capabilities")] - public EnvironmentCapabilities? Capabilities { get; set; } - - /// Identifier assigned by Mission Control. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Compute kind reported by Mission Control. - [JsonPropertyName("kind")] - public EnvironmentKind Kind { get; set; } - - /// Discovery labels attached to the environment. - [JsonPropertyName("labels")] - public IDictionary? Labels { get; set; } - - /// Timestamp of the last heartbeat received by Mission Control. - [JsonPropertyName("lastHeartbeatAt")] - public string? LastHeartbeatAt { get; set; } - - /// Human-readable environment name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Organization identifier, when the environment belongs to an organization. - [JsonPropertyName("orgId")] - public string? OrgId { get; set; } - - /// Identifier of the environment owner. - [JsonPropertyName("ownerId")] - public string? OwnerId { get; set; } - - /// Owner category reported by Mission Control. - [JsonPropertyName("ownerType")] - public string? OwnerType { get; set; } + /// The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. + [JsonPropertyName("managedSandbox")] + public JsonElement? ManagedSandbox { get; set; } - /// Open-ended operational status vocabulary. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; + /// The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. + [JsonPropertyName("userSandbox")] + public JsonElement? UserSandbox { get; set; } } -/// Environments visible to the authenticated caller and matching the supplied filters. +/// The prepared file-picker policy, or none when the sandbox is disabled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentsListResult +internal sealed class SandboxPreparePickerPolicyResult { - /// Safe discovery records without relay bootstrap credentials. - [JsonPropertyName("environments")] - public IList Environments { get => field ??= []; set; } + /// The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the sandbox is disabled or absent, in which case filtering keeps every candidate. + [JsonPropertyName("sandboxJson")] + public JsonElement? SandboxJson { get; set; } } -/// Optional discovery filters supported by GitHub Mission Control. +/// The working directory and sandbox settings to build a file-picker policy from. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnvironmentsListRequest +internal sealed class SandboxPreparePickerPolicyParams { - /// Restrict discovery to this compute kind. - [JsonPropertyName("kind")] - public EnvironmentKind? Kind { get; set; } + /// The session's working directory. Git discovery and grant canonicalization are resolved against it. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// Operational status, such as online, offline, degraded, waking, or draining. - [JsonPropertyName("status")] - public string? Status { get; set; } + /// The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. + [JsonPropertyName("sandbox")] + public JsonElement? Sandbox { get; set; } } -/// Safe discovery information for the requested environment. +/// Per-candidate allow decisions, positionally aligned with the request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentsGetResult +internal sealed class SandboxFilterPickerCandidatesResult { - /// The requested environment without relay bootstrap credentials. - [JsonPropertyName("environment")] - public GitHubEnvironment Environment { get => field ??= new(); set; } + /// One decision per candidate, in the same order. Always the same length as the request's `candidates`. + [JsonPropertyName("allowed")] + public IList Allowed { get => field ??= []; set; } } -/// Identify a Mission Control environment to retrieve. +/// One file-picker suggestion offered up for the sandbox filesystem check. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnvironmentsGetRequest +internal sealed class SandboxPickerCandidate { - /// Identifier assigned by Mission Control. - [JsonPropertyName("environmentId")] - public string EnvironmentId { get; set; } = string.Empty; + /// Whether the suggestion is a directory. A directory the policy does not itself allow may still be needed as a waypoint to an allowed subtree. + [JsonPropertyName("isDirectory")] + public bool IsDirectory { get; set; } + + /// Absolute path the suggestion would attach. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Acknowledgement that the requested environment was deleted. +/// A batch of file-picker candidates to check against a prepared policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentsDeleteResult +internal sealed class SandboxFilterPickerCandidatesParams { + /// The candidates to check, in the order the answers are returned. + [JsonPropertyName("candidates")] + public IList Candidates { get => field ??= []; set; } + + /// The session's working directory, matching the one the policy was prepared from. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; + + /// The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. + [JsonPropertyName("sandbox")] + public JsonElement? Sandbox { get; set; } } -/// Identify a user-managed Mission Control environment to delete. +/// The sandbox a named feature actually launches under. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnvironmentsDeleteRequest +internal sealed class SandboxEffectiveForOptionalResult { - /// User-managed environment to delete. GitHub-managed environments cannot be deleted. - [JsonPropertyName("environmentId")] - public string EnvironmentId { get; set; } = string.Empty; + /// The effective sandbox config for the requested feature, or a disabled sandbox when the feature is routed out of it. + [JsonPropertyName("sandboxJson")] + public JsonElement SandboxJson { get; set; } } -/// The existing runtime identity and its resource on the listener. +/// A sandbox config and the per-feature routing flag to resolve it for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostPublishSessionResult +internal sealed class SandboxEffectiveForOptionalParams { - /// Canonical runtime ID of the published session. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. + [JsonPropertyName("routingFlag")] + public string RoutingFlag { get; set; } = string.Empty; - /// AHP resource URI for the session on this listener. - [JsonPropertyName("sessionUri")] - public string SessionUri { get; set; } = string.Empty; + /// The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. + [JsonPropertyName("sandbox")] + public JsonElement? Sandbox { get; set; } } -/// Publishes a resident session attached to the listener's owning connection. +/// The startup warning, absent when the machine can run a sandbox. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostPublishSessionRequest +internal sealed class SandboxUnsupportedStartupNoticeResult { - /// Listener UUID returned by host.start. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; - - /// Canonical runtime session ID attached to the listener's owning connection. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The user-facing warning, carrying the platform remedy and the recovery the policy in force actually allows. Absent when this machine supports a sandbox, so a host can call unconditionally and print only what it gets. + [JsonPropertyName("notice")] + public string? Notice { get; set; } } -/// The resident session the application has materialized on its own connection. +/// The managed sandbox policy in force, which selects which remedy the notice offers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostCreateSessionResult +internal sealed class SandboxUnsupportedStartupNoticeParams { - /// Runtime session UUID materialized on the application's SDK connection. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. + [JsonPropertyName("enabledByUndeterminedPolicy")] + public bool? EnabledByUndeterminedPolicy { get; set; } + + /// The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. + [JsonPropertyName("managedSandbox")] + public JsonElement? ManagedSandbox { get; set; } } -/// One application-owned session handoff, requested by the supervised hosting participant. +/// One slash command, as typed, to test against the enforcement-block allowlist. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostCreateSessionRequest +internal sealed class SandboxEnforcementCommandAllowedParams { - /// Host-selected SDK creation or resume settings, without executable callbacks or tools. - [JsonPropertyName("config")] - public IDictionary Config { get => field ??= new Dictionary(); set; } - - /// Unique identity for this participation, independent of the session lifetime. - [JsonPropertyName("handoffId")] - public string HandoffId { get; set; } = string.Empty; + /// The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. + [JsonPropertyName("args")] + public IList Args { get => field ??= []; set; } - /// Resume an app-owned durable session instead of creating a new session. - [JsonPropertyName("resume")] - public bool? Resume { get; set; } + /// The command name as the user typed it, with or without its leading slash. + [JsonPropertyName("commandName")] + public string CommandName { get; set; } = string.Empty; } -/// Empty acknowledgement for a completed host lifecycle operation. +/// The documentation URL a host cites when it declines or downgrades a sandbox setting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReleaseSessionResult +internal sealed class SandboxDocsUrlResult { + /// Documentation URL describing the sandbox and the settings that control it. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// Ends one participation, not the application's session lifetime. +/// Whether this host can run one sandbox policy feature. A session whose effective policy uses an unsupported feature fails each sandboxed command with `reason`, except `filesystem_enumeration`, whose absence degrades sandboxed PowerShell instead of failing it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReleaseSessionRequest +public sealed class SandboxHostCapability { - /// Identity of the participation to release without destroying the session. - [JsonPropertyName("handoffId")] - public string HandoffId { get; set; } = string.Empty; + /// The policy feature, as an extensible string: ignore names you do not recognize. Known values: `network` (sandboxed commands can reach the network; on Linux this needs the tooling for Bubblewrap's private network namespace, such as slirp4netns), `network_filtering` (host rules and the sandbox proxy; on Linux this needs the same tooling as `network`; on Windows it needs Process Security Environment 1.1 host-loopback support or MXC's PSEC 1.0-only proxy-loopback compatibility capability, and a policy that uses it must also set `network.allowLocalNetwork`; compatibility applies only to an explicit identity-less runtime proxy, not general host-loopback access, and other policy restrictions still apply), `denied_paths` (native enforcement of `filesystem.deniedPaths`), `shell` (shell commands inside the sandbox), and `filesystem_enumeration` (enumerate-only filesystem grants; on Windows this needs Process Security Environment 1.1 filesystem enumeration support, and without it sandboxed PowerShell still runs but cannot resolve its current location; other platforms always report it). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Human-readable reason and remedy when the feature is unsupported, such as a package to install or an OS update. Present only when `supported` is false. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether this host can run the feature. + [JsonPropertyName("supported")] + public bool Supported { get; set; } } -/// Listener readiness, returned only after binding and the supervised participant's SDK handshake. +/// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostStartResult +public sealed class SandboxHostSupport { - /// GitHub Mission Control environment ID, present when its relay transport is ready. - [JsonPropertyName("environmentId")] - public string? EnvironmentId { get; set; } - - /// Caller-generated listener UUID. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; - - /// Separate host process ID, when provided by a legacy runtime. Absent for in-process listeners. - [JsonPropertyName("pid")] - public long? Pid { get; set; } + /// Sandbox policy features whose availability varies between hosts that can run the backend. Empty when `supported` is false, because no feature can run without a backend. Later runtimes can add entries; ignore an entry whose `name` you do not recognize. + [JsonPropertyName("capabilities")] + public IList Capabilities { get => field ??= []; set; } - /// Secret connection token, absent when authentication is disabled. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Human-readable reason the sandbox cannot run on this host. Present only when `supported` is false. + [JsonPropertyName("reason")] + public string? Reason { get; set; } - /// Actual bound WebSocket URL, including the allocated port. - [JsonPropertyName("url")] - public string? Url { get; set; } + /// Whether a process-containment backend is usable on this host: Seatbelt on macOS, Bubblewrap on Linux, or ProcessContainer on Windows. + [JsonPropertyName("supported")] + public bool Supported { get; set; } } -/// GitHub Mission Control registration options. The compute ID is application-owned and stable. +/// Credential-injection capability flags applied while the sandbox is enabled. For the same capability independent of sandboxing, and matched to the credential's GitHub host, see `shell.credentials`; the two are additive. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostGitHubEnvironmentOptions +public sealed class SandboxConfigAuth { - /// Stable application installation identity, reused across host restarts. - [JsonPropertyName("computeId")] - public string ComputeId { get; set; } = string.Empty; + /// Whether to authenticate sandboxed gh through the local masking proxy. The child receives a fake GH_TOKEN; its real value is substituted only at github.com, api.github.com and uploads.github.com (github.com because gh repo clone authenticates git through gh auth git-credential). The repository's GitHub account takes precedence over the Copilot login. Default: false (opt-in). + [JsonPropertyName("gh")] + public bool? Gh { get; set; } - /// Human-readable environment display name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether to authenticate sandboxed HTTPS git through the local masking proxy. The child receives a fake `http.<url>.extraheader`; the real Authorization header is substituted only at its original HTTPS host, port, and repository path scope. github.com uses the Copilot token; other forges use credentials resolved from the user's own helper on the host. Default: false (opt-in). + [JsonPropertyName("git")] + public bool? Git { get; set; } } -/// Local WebSocket transport options. +/// Destinations authorized to receive one masked environment credential. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostLocalServerOptions +public sealed class SandboxMaskedEnvVar { - /// Listener hostname. Defaults to 127.0.0.1; explicit non-loopback binds are allowed. - [JsonPropertyName("hostname")] - public string? Hostname { get; set; } - - /// Listener port. Omitted or zero requests an OS-allocated port. - [JsonPropertyName("port")] - public int? Port { get; set; } - - /// Require token authentication (default true). Cannot be false with a token. - [JsonPropertyName("requireConnectionToken")] - public bool? RequireConnectionToken { get; set; } - - /// Nonempty connection token. Generated randomly when required and omitted. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Nonempty list of HTTPS injection hostnames or *.example.com patterns. Bare * is not accepted. These grants never override the sandbox network policy. Values in plaintext HTTP requests, URLs, bodies, encoded credentials, and signed requests are not substituted. + [JsonPropertyName("injectHosts")] + public IList InjectHosts { get => field ??= []; set; } } -/// Starts a supervised AHP host with at least one explicitly selected transport. +/// Whole-value environment credential masking for sandboxed children. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostStartRequest +public sealed class SandboxCredentialsConfig { - /// Registers a GitHub Mission Control environment and enables its relay transport. - [JsonPropertyName("githubEnvironment")] - public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } - - /// Caller-generated UUID identifying this connection-owned listener. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; - - /// Enables a local WebSocket listener. - [JsonPropertyName("localServer")] - public HostLocalServerOptions? LocalServer { get; set; } - - /// Ask the owning application to resume its durable AHP sessions. - [JsonPropertyName("resumeFactory")] - public bool? ResumeFactory { get; set; } - - /// Ask the owning SDK application to materialize AHP sessions. - [JsonPropertyName("sessionFactory")] - public bool? SessionFactory { get; set; } + /// Environment variable names and their HTTPS injection destinations. Absent variables stay absent. No real values or sentinels are stored in this map. + [JsonPropertyName("envVars")] + public IDictionary EnvVars { get => field ??= new Dictionary(); set; } } -/// Empty acknowledgement for a completed host lifecycle operation. +/// macOS seatbelt experimental options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostDisposeResult +public sealed class SandboxConfigUserPolicyExperimentalSeatbelt { + /// Whether the macOS seatbelt profile may access the keychain. + [JsonPropertyName("keychainAccess")] + public bool? KeychainAccess { get; set; } } -/// Stops a connection-owned listener and joins its teardown. +/// Platform-specific experimental policy fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostDisposeRequest +public sealed class SandboxConfigUserPolicyExperimental { - /// Listener UUID. Unknown or successfully stopped IDs are harmless. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; + /// macOS seatbelt experimental options. + [JsonPropertyName("seatbelt")] + public SandboxConfigUserPolicyExperimentalSeatbelt? Seatbelt { get; set; } } -/// Private credentials delivered only to a runtime-owned Mission Control hosting participant. +/// Filesystem rules to merge into the base policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostGetEnvironmentCredentialsResult +public sealed class SandboxConfigUserPolicyFilesystem { - /// GitHub API base URL for the authenticated service. - [JsonPropertyName("githubApiUrl")] - public string GitHubApiUrl { get; set; } = string.Empty; + /// Whether to clear the policy when the session exits. + [JsonPropertyName("clearPolicyOnExit")] + public bool? ClearPolicyOnExit { get; set; } - /// Hostname of the authenticated GitHub service. - [JsonPropertyName("githubHost")] - public string GitHubHost { get; set; } = string.Empty; + /// Paths explicitly denied. + [JsonPropertyName("deniedPaths")] + public IList? DeniedPaths { get; set; } - /// Mission Control API origin for environment registration and management. - [JsonPropertyName("missionControlUrl")] - public string MissionControlUrl { get; set; } = string.Empty; + /// Paths granted read-only access. + [JsonPropertyName("readonlyPaths")] + public IList? ReadonlyPaths { get; set; } - /// Current bearer token for the authenticated GitHub identity. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// Paths granted read/write access. + [JsonPropertyName("readwritePaths")] + public IList? ReadwritePaths { get; set; } } -/// Normalized local WebSocket listener settings. +/// HTTP proxy configuration for sandboxed traffic. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostLocalServerConfiguration +public sealed class SandboxConfigUserPolicyNetworkProxy { - /// Hostname or IP address to bind. - [JsonPropertyName("hostname")] - public string Hostname { get; set; } = string.Empty; - - /// Port to bind, with zero requesting OS allocation. - [JsonPropertyName("port")] - public int Port { get; set; } + /// Optional password for proxy authentication, combined with the URL at spawn time. The persisted value may be a literal password, a `${secret:…}` reference resolved from the OS keychain, or a `${VAR}`/`$VAR` environment reference; it is resolved just before the sandboxed process routes through the proxy. The /sandbox dialog stores a real password in the OS keychain and persists only a `${secret:…}` placeholder (never plaintext in settings.json); the field is masked in the dialog and redacted by /settings show. + [JsonPropertyName("password")] + public string? Password { get; set; } - /// Whether the listener requires token authentication. - [JsonPropertyName("requireConnectionToken")] - public bool RequireConnectionToken { get; set; } + /// Proxy URL (e.g. http://proxy.example.com:8080). The port is optional and defaults to the scheme's standard port when omitted; an explicit port must be between 1 and 65535. Credentials must not be embedded here — a `user:pass@` authority is rejected; put them in the separate `username`/`password` fields. A credential-free http:// loopback proxy URL is routed through the localhost proxy automatically; loopback covers localhost and any *.localhost subdomain, the whole 127.0.0.0/8 range, ::1, and IPv4-mapped loopback (::ffff:127.0.0.1). An https:// URL, or one with a username/password set, is used as-is. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; - /// Secret connection token, absent when authentication is disabled. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Optional username for proxy authentication. Combined with the URL (and `password`) into `user:pass@host` when the sandboxed process routes through the proxy. + [JsonPropertyName("username")] + public string? Username { get; set; } } -/// Normalized listener settings delivered only to the supervised hosting participant. +/// Network rules to merge into the base policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostGetConfigurationResult +public sealed class SandboxConfigUserPolicyNetwork { - /// Requested GitHub Mission Control registration. - [JsonPropertyName("githubEnvironment")] - public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } + /// Hosts allowed through the built-in sandbox proxy. A non-empty list denies unmatched hosts; an absent or empty list allows all hosts not blocked. Supports exact hostnames, IP addresses, and *.example.com for strict subdomains. Host rules do not override the outbound or local-network toggles. + [JsonPropertyName("allowedHosts")] + public IList? AllowedHosts { get; set; } - /// Normalized local listener settings, absent for relay-only hosts. - [JsonPropertyName("localServer")] - public HostLocalServerConfiguration? LocalServer { get; set; } + /// Whether traffic to local/loopback addresses is allowed. + [JsonPropertyName("allowLocalNetwork")] + public bool? AllowLocalNetwork { get; set; } - /// Whether app-owned durable sessions are resumed by the owning application. - [JsonPropertyName("resumeFactory")] - public bool ResumeFactory { get; set; } + /// Whether outbound network traffic is allowed at all. + [JsonPropertyName("allowOutbound")] + public bool? AllowOutbound { get; set; } - /// Whether session materialization is delegated to the owning application. - [JsonPropertyName("sessionFactory")] - public bool SessionFactory { get; set; } + /// Hosts denied by the built-in sandbox proxy. Deny rules take precedence over allowedHosts. A domain also denies all its subdomains. IP addresses match exactly; *.example.com matches strict subdomains, and * denies every host. + [JsonPropertyName("blockedHosts")] + public IList? BlockedHosts { get; set; } + + /// HTTP(S) proxy for sandboxed traffic. This is the built-in local proxy's upstream: every sandboxed command reaches it through a loopback listener, so credentials stay in the runtime and never reach the child. On Windows the sandbox also needs local network access, because it reaches that listener over host loopback. Configure credentials in the separate username/password fields. The transient local listener URL is never persisted. + [JsonPropertyName("proxy")] + public SandboxConfigUserPolicyNetworkProxy? Proxy { get; set; } } -/// Empty acknowledgement for a completed host lifecycle operation. +/// macOS seatbelt-specific options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReadyResult +public sealed class SandboxConfigUserPolicySeatbelt { + /// Whether the macOS seatbelt profile may access the keychain. + [JsonPropertyName("keychainAccess")] + public bool? KeychainAccess { get; set; } } -/// Readiness reported by the supervised hosting participant on its own SDK connection. +/// User-managed sandbox policy fragment merged into the auto-discovered base policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReadyRequest +public sealed class SandboxConfigUserPolicy { - /// Actual bound WebSocket URL. - [JsonPropertyName("address")] - public string? Address { get; set; } + /// Deprecated legacy location for `seatbelt`; read only when the top-level `seatbelt` is absent. + [JsonPropertyName("experimental")] + public SandboxConfigUserPolicyExperimental? Experimental { get; set; } - /// Registered environment ID, reported only once the relay transport is connected. - [JsonPropertyName("environmentId")] - public string? EnvironmentId { get; set; } + /// Filesystem rules to merge into the base policy. + [JsonPropertyName("filesystem")] + public SandboxConfigUserPolicyFilesystem? Filesystem { get; set; } - /// Configured secret token, absent when authentication is disabled. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Network rules to merge into the base policy. + [JsonPropertyName("network")] + public SandboxConfigUserPolicyNetwork? Network { get; set; } + + /// macOS seatbelt options to merge into the base policy. + [JsonPropertyName("seatbelt")] + public SandboxConfigUserPolicySeatbelt? Seatbelt { get; set; } } -/// One server-discovered hook action from user, repository, plugin, or managed-policy configuration. +/// Resolved sandbox configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredHook +public sealed class SandboxConfig { - /// Durable content hash used by hook enablement. Identical actions may intentionally share this key. Omitted when changing the user's disabled-hooks setting cannot change the action's current server-discovered state, including managed-policy hooks, session-start prompt actions, actions suppressed by disable-all settings, and projectless plugin actions that require project-directory expansion. - [JsonPropertyName("disableKey")] - public string? DisableKey { get; set; } + /// Whether to auto-add the current working directory to readwritePaths. Default: true. + [JsonPropertyName("addCurrentWorkingDirectory")] + public bool? AddCurrentWorkingDirectory { get; set; } - /// Whether this action is enabled under the server-side discovery settings. Concrete sessions may differ because they can add session-specific directories, plugins, or trust. False when its disable key is present in the user's disabled-hooks setting or disable-all settings suppress the action. + /// Whether the agent may request that an individual command run outside the sandbox, which the host then approves or denies through the usual permission flow. A host capability flag rather than part of the policy: it is stripped from the effective spawn policy and only has an effect while `enabled` is true. Fail-closed, unlike the opt-out flags on this object: omitting it offers no bypass. Default: false (opt-in). + [JsonPropertyName("allowBypass")] + public bool? AllowBypass { get; set; } + + /// Whether to auto-grant read access to tool directories discovered on PATH and in toolchain environment variables (GOROOT, JAVA_HOME, VIRTUAL_ENV, and similar), and to common developer-tool caches, config, and toolchains. Writable grants cover scratch caches, the Unix GitHub CLI cache, and Cargo's registry, git store, and lock/tracker files. A relocated CARGO_HOME gets the same narrow split: registry and git are read-write; bin is read-only; the home root, config.toml, and credentials.toml stay ungranted. Set to false to disable every grant listed above; user-installed toolchains and caches then need explicit userPolicy.filesystem readonlyPaths and readwritePaths entries. The working directory (see addCurrentWorkingDirectory), temporary storage, session log paths, and system locations follow their own rules and stay granted. Default: true (enabled by default; set to false to opt out). + [JsonPropertyName("allowDevToolAccess")] + public bool? AllowDevToolAccess { get; set; } + + /// Credential-injection capability flags. + [JsonPropertyName("auth")] + public SandboxConfigAuth? Auth { get; set; } + + /// Opt-in whole-value environment masking for sandboxed shell, MCP, and LSP children. Configured names get random sentinels; the local proxy substitutes them only in HTTPS request headers at their injection hosts. Approved bypasses skip masking and the sandbox proxy, so bypassed shells may receive the real environment values. Disabled or explicitly opted-out routes are not protected. No credential values are stored in this configuration. + [JsonPropertyName("credentials")] + public SandboxCredentialsConfig? Credentials { get; set; } + + /// Whether sandboxing is enabled for the session. [JsonPropertyName("enabled")] public bool Enabled { get; set; } - /// Hook event that invokes this action. - [JsonPropertyName("hookType")] - public HookType HookType { get; set; } + /// The `sandboxLspServers` counterpart of `managedMcpRoutingLocked`. + [JsonInclude] + [JsonPropertyName("managedLspRoutingLocked")] + internal bool? ManagedLspRoutingLocked { get; set; } - /// Deterministic identifier for this server-discovered action row. It remains stable while the project, origin, source, event, action content, and duplicate ordinal are unchanged. This is row identity, not the key persisted in disabledHooks. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Set by the runtime when a managed policy forced `sandboxMcpServers` on and took the local opt-out away. Provenance rather than policy: it lets a sandbox startup failure point at the administrator instead of a setting the next managed merge would override, and it is ignored when comparing two configs for change. Only the managed merge may set it; a caller-supplied value is stripped. + [JsonInclude] + [JsonPropertyName("managedMcpRoutingLocked")] + internal bool? ManagedMcpRoutingLocked { get; set; } - /// Configuration tier that contributed this hook action. - [JsonPropertyName("origin")] - public HookOrigin Origin { get; set; } + /// Whether language servers the session launches are confined by the sandbox. Only an explicit `false` opts out. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). + [JsonPropertyName("sandboxLspServers")] + public bool? SandboxLspServers { get; set; } - /// Input project path for which this server-side action was resolved. Set on every row returned for project-scoped discovery, including repeated user and policy actions. - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } + /// Whether MCP servers the session launches are confined by the sandbox. Only an explicit `false` opts out; doing so also lets remote-MCP egress leave the sandbox, so the flag and `enabled` are always read together. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). + [JsonPropertyName("sandboxMcpServers")] + public bool? SandboxMcpServers { get; set; } - /// Human-readable source label, such as a hook file path, settings source, or plugin name. - [JsonPropertyName("source")] - public string? Source { get; set; } + /// User-managed sandbox policy fragment merged into the auto-discovered base policy. + [JsonPropertyName("userPolicy")] + public SandboxConfigUserPolicy? UserPolicy { get; set; } } -/// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. +/// Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HooksDiscoverResult +internal sealed class SandboxProxyCaRequest { - /// Errors for hook sources or actions that could not be loaded, making the result partially incomplete. Other valid actions are still returned. Project-resolution and repository-settings errors are prefixed with their project path. - [JsonPropertyName("errors")] - public IList Errors { get => field ??= []; set; } + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + [JsonPropertyName("sandboxConfig")] + public SandboxConfig? SandboxConfig { get; set; } +} - /// All discovered hook actions. Byte-identical actions remain separate rows even when they share a disable key. - [JsonPropertyName("hooks")] - public IList Hooks { get => field ??= []; set; } +/// Status of the persistent certificate authority of the sandbox credential proxy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SandboxProxyCaStatus +{ + /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. + [JsonPropertyName("canInstall")] + public bool CanInstall { get; set; } - /// Non-fatal source-loading warnings. Discovery remains complete for the affected source, although the source had a recoverable issue. Repository-settings warnings are prefixed with their project path when attribution is available. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. + [JsonPropertyName("detail")] + public string? Detail { get; set; } + + /// The state of the certificate authority. + [JsonPropertyName("state")] + public SandboxProxyCaState State { get; set; } } -/// Optional project paths and host-exclusion behavior for server-scoped hook discovery. +/// Result of creating the persistent certificate authority of the sandbox credential proxy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HooksDiscoverRequest +public sealed class SandboxProxyCaCreateResult { - /// When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. - [JsonPropertyName("excludeHostHooks")] - public bool? ExcludeHostHooks { get; set; } - - /// Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Absolute path of the public certificate of the certificate authority, in PEM format. + [JsonPropertyName("certificatePath")] + public string CertificatePath { get; set; } = string.Empty; } -/// Active server-driven promotion for a model, including its discount and optional expiry. +/// Where this runtime keeps the sandbox proxy password. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBillingPromo +internal sealed class SandboxProxySecretLocation { - /// Percentage discount (0-100) applied while the promotion is active. May be fractional. - [JsonPropertyName("discountPercent")] - public double? DiscountPercent { get; set; } + /// Absolute path of the credential store holding the sandbox proxy password. The proxy password belongs to no MCP server, so it is kept in its own directory rather than in the MCP secret store. + [JsonPropertyName("configDir")] + public string ConfigDir { get; set; } = string.Empty; - /// UTC ISO 8601 timestamp marking when the promotion ends. Optional: an open-ended promotion omits this field. When present, the API only surfaces a promo whose expiry parses and is in the future, so consumers should treat a past value as expired. - [JsonPropertyName("endsAt")] - public string? EndsAt { get; set; } + /// Identifier of the proxy password entry within that store. Derived from the configuration directory, so two Copilot homes on one machine never share an entry. Use it to recognize a `${secret:…}` reference in stored settings as this runtime's own proxy password. + [JsonPropertyName("secretId")] + public string SecretId { get; set; } = string.Empty; +} - /// Stable identifier for the promotion campaign. - [JsonPropertyName("id")] - public string? Id { get; set; } +/// The stored sandbox proxy password, if one is present. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxProxySecretGetResult +{ + /// The stored password. Absent when no entry exists in either the keychain or the on-disk fallback store. + [JsonPropertyName("value")] + public string? Value { get; set; } +} - /// Human-readable promotion message. Does not include the expiry timestamp; consumers may format endsAt and append it when present. - [JsonPropertyName("message")] - public string? Message { get; set; } - - /// Whether the service asked hosts to give this promotion a prominent surface, such as a dedicated banner, in addition to listing it with the model. `true` requests that surface and `false` asks for the model list only. Absent means the service expressed no preference — for example a response that predates the field — so hosts should apply their own default rather than read it as `false`. - [JsonPropertyName("showBanner")] - public bool? ShowBanner { get; set; } +/// Where the sandbox proxy password was stored. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxProxySecretSaveResult +{ + /// Whether the OS keychain accepted the value. False means it was written to the on-disk fallback store instead, which is still readable by `sandbox.proxySecret.get`. + [JsonPropertyName("storedInKeychain")] + public bool StoredInKeychain { get; set; } } -/// Long context tier pricing (available for models with extended context windows). +/// The sandbox proxy password to store. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBillingTokenPricesLongContext +internal sealed class SandboxProxySecretSaveRequest { - /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("cachePrice")] - public double? CachePrice { get; set; } - - /// AI Credits cost per billing batch of cached (read) tokens. - [JsonPropertyName("cacheReadPrice")] - public double? CacheReadPrice { get; set; } + /// The password to store for the sandbox proxy. + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; +} - /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. - [JsonPropertyName("cacheWrite1hPrice")] - public double? CacheWrite1hPrice { get; set; } +/// The stored sandbox settings to resolve against the defaults. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxApplyDefaultsRequest +{ + /// The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. + [JsonPropertyName("stored")] + public JsonElement Stored { get; set; } +} - /// AI Credits cost per billing batch of cache-write (cache creation) tokens. - [JsonPropertyName("cacheWritePrice")] - public double? CacheWritePrice { get; set; } +/// The outcome of a locked snapshot write. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PersistenceWriteRawJsonLockedResult +{ + /// Why the write failed. Absent when `success` is true. A lock the runtime could not acquire in time reports here rather than raising. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Use maxPromptTokens instead. Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("contextMax")] - public long? ContextMax { get; set; } + /// Whether the file now holds the requested contents. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// AI Credits cost per billing batch of input tokens. - [JsonPropertyName("inputPrice")] - public double? InputPrice { get; set; } +/// A complete JSON snapshot to write under the runtime's per-path file lock. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PersistenceWriteRawJsonLockedRequest +{ + /// The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. + [JsonPropertyName("dataJson")] + public string DataJson { get; set; } = string.Empty; - /// Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. - [JsonPropertyName("maxPromptTokens")] - public long? MaxPromptTokens { get; set; } + /// Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. + [JsonPropertyName("fileHeader")] + public string? FileHeader { get; set; } - /// AI Credits cost per billing batch of output tokens. - [JsonPropertyName("outputPrice")] - public double? OutputPrice { get; set; } + /// Absolute path of the file to replace. Parent directories are created when missing. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Token-level pricing information for this model. +/// Outcome of rewriting the `disabledHooks` setting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBillingTokenPrices +internal sealed class UserSettingsSetHookDisabledResult { - /// Number of tokens per standard billing batch. - [JsonPropertyName("batchSize")] - public long? BatchSize { get; set; } - - /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("cachePrice")] - public double? CachePrice { get; set; } - - /// AI Credits cost per billing batch of cached (read) tokens. - [JsonPropertyName("cacheReadPrice")] - public double? CacheReadPrice { get; set; } + /// Why the write failed. Absent when the status is `ok`. + [JsonPropertyName("errorMessage")] + public string? ErrorMessage { get; set; } - /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. - [JsonPropertyName("cacheWrite1hPrice")] - public double? CacheWrite1hPrice { get; set; } + /// `ok` when the setting was written, `invalid` when settings.json could not be parsed and was left alone, `error` when the write itself failed. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; +} - /// AI Credits cost per billing batch of cache-write (cache creation) tokens. - [JsonPropertyName("cacheWritePrice")] - public double? CacheWritePrice { get; set; } +/// One hook to disable or re-enable. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsSetHookDisabledRequest +{ + /// True adds the key to `disabledHooks`, false removes it. + [JsonPropertyName("disabled")] + public bool Disabled { get; set; } - /// Use maxPromptTokens instead. Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("contextMax")] - public long? ContextMax { get; set; } + /// Durable content-hash key of the hook, as `hooks.loadResources` reports it. + [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("disableKey")] + public string DisableKey { get; set; } = string.Empty; - /// AI Credits cost per billing batch of input tokens. - [JsonPropertyName("inputPrice")] - public double? InputPrice { get; set; } + /// Path of the settings.json to rewrite. + [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("settingsPath")] + public string SettingsPath { get; set; } = string.Empty; +} - /// Long context tier pricing (available for models with extended context windows). - [JsonPropertyName("longContext")] - public ModelBillingTokenPricesLongContext? LongContext { get; set; } +/// Selects the configuration directory whose user settings to read. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsLoadForConfigDirRequest +{ + /// Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } +} - /// Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. - [JsonPropertyName("maxPromptTokens")] - public long? MaxPromptTokens { get; set; } +/// A repository's settings as stored, together with any diagnostic raised while reading them. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsLoadRepoResult +{ + /// The repository's settings document, keyed by setting name, with each value carried verbatim. Null when the repository declares no settings. + [JsonPropertyName("settings")] + public IDictionary? Settings { get; set; } - /// AI Credits cost per billing batch of output tokens. - [JsonPropertyName("outputPrice")] - public double? OutputPrice { get; set; } + /// Why part of the document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer should surface this and continue rather than treat it as a failure. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Billing information. +/// Selects the repository whose checked-in settings to read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBilling +internal sealed class UserSettingsLoadRepoRequest { - /// Whole-number percentage discount (0-100) applied to usage billed through this model. Populated for the synthetic `auto` model, where requests routed by auto-mode are billed at a reduced rate; absent for concrete models. - [JsonPropertyName("discountPercent")] - public int? DiscountPercent { get; set; } - - /// Billing cost multiplier relative to the base rate. - [JsonPropertyName("multiplier")] - public double? Multiplier { get; set; } + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; +} - /// Active server-driven promotion for this model, if any. Present when the model is being promoted with a discount, which may be time-boxed or open-ended. - [JsonPropertyName("promo")] - public ModelBillingPromo? Promo { get; set; } +/// The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsLoadAndMergeRepoResult +{ + /// The merged settings document, keyed by setting name. Equals the supplied user layer when the repository declares no settings. + [JsonPropertyName("settings")] + public IDictionary Settings { get => field ??= new Dictionary(); set; } - /// Token-level pricing information for this model. - [JsonPropertyName("tokenPrices")] - public ModelBillingTokenPrices? TokenPrices { get; set; } + /// Why part of the repository document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did load are still merged, so a consumer should surface this and continue rather than treat it as a failure. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Vision-specific limits. +/// A repository to read settings from, and the user layer they are merged over. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesLimitsVision +internal sealed class UserSettingsLoadAndMergeRepoRequest { - /// Maximum image size in bytes. - [JsonPropertyName("max_prompt_image_size")] - public long MaxPromptImageSize { get; set; } - - /// Maximum number of images per prompt. - [JsonPropertyName("max_prompt_images")] - public long MaxPromptImages { get; set; } + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// MIME types the model accepts. - [JsonPropertyName("supported_media_types")] - public IList SupportedMediaTypes { get => field ??= []; set; } + /// The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. + [JsonPropertyName("userSettings")] + public IDictionary UserSettings { get => field ??= new Dictionary(); set; } } -/// Token limits for prompts, outputs, and context window. +/// The on-disk location of the user's settings document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesLimits +internal sealed class UserSettingsPathResult { - /// Maximum total context window size in tokens. - [JsonPropertyName("max_context_window_tokens")] - public long? MaxContextWindowTokens { get; set; } + /// Absolute path to the settings file this runtime reads and writes. Normally `settings.json` under the Copilot configuration directory; an extensionless legacy `settings` file is reported instead when it exists and `settings.json` does not. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} - /// Maximum number of output/completion tokens. - [JsonPropertyName("max_output_tokens")] - public long? MaxOutputTokens { get; set; } +/// The user's stored settings, together with any diagnostic raised while reading them. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsLoadWithWarningResult +{ + /// The stored user settings document, keyed by setting name, with each value carried verbatim. Empty when the file could not be read at all. + [JsonPropertyName("settings")] + public IDictionary Settings { get => field ??= new Dictionary(); set; } - /// Maximum number of prompt/input tokens. - [JsonPropertyName("max_prompt_tokens")] - public long? MaxPromptTokens { get; set; } + /// Why part of the document was ignored, phrased for display to the user. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer may surface this and continue rather than treat it as a failure. + [JsonPropertyName("warning")] + public string? Warning { get; set; } +} - /// Vision-specific limits. - [JsonPropertyName("vision")] - public ModelCapabilitiesLimitsVision? Vision { get; set; } +/// The user layer folded over the managed layer. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsMergeManagedAndUserResult +{ + /// The merged settings. An empty object when neither layer was supplied, so an unmanaged host with no user settings governs nothing. + [JsonPropertyName("settingsJson")] + public JsonElement SettingsJson { get; set; } } -/// Feature flags indicating what the model supports. +/// The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesSupports +internal sealed class UserSettingsMergeManagedAndUserParams { - /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). - [JsonPropertyName("adaptive_thinking")] - public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } + /// The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. + [JsonPropertyName("managed")] + public JsonElement? Managed { get; set; } - /// Whether this model supports reasoning effort configuration. - [JsonPropertyName("reasoningEffort")] - public bool? ReasoningEffort { get; set; } + /// The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. + [JsonPropertyName("user")] + public JsonElement? User { get; set; } +} - /// Whether the model supports provider-native thinking. Independent of configurable reasoning effort; omission means unknown. - [JsonPropertyName("thinking")] - public bool? Thinking { get; set; } +/// The repository layer folded into the user layer. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsMergeRepoValueResult +{ + /// The merged settings, with the per-entry managed control maps re-stamped from the runtime's ambient managed policy. + [JsonPropertyName("settingsJson")] + public JsonElement SettingsJson { get; set; } +} - /// Whether this model supports canonical tool calling. - [JsonPropertyName("toolCalls")] - public bool? ToolCalls { get; set; } +/// The user layer and the repository layer to fold together. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsMergeRepoValueParams +{ + /// The repository's checked-in settings layer. + [JsonPropertyName("repoSettings")] + public JsonElement RepoSettings { get; set; } - /// Whether this model supports vision/image input. - [JsonPropertyName("vision")] - public bool? Vision { get; set; } + /// The user's settings, already resolved against any managed layer. + [JsonPropertyName("userSettings")] + public JsonElement UserSettings { get; set; } } -/// Model capabilities and limits. +/// The outcome of the one-time staff update-channel migration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilities +internal sealed class UserSettingsMigrateStaffUpdateChannelOnceResult { - /// Token limits for prompts, outputs, and context window. - [JsonPropertyName("limits")] - public ModelCapabilitiesLimits? Limits { get; set; } + /// When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. + [JsonPropertyName("completedAt")] + public string? CompletedAt { get; set; } - /// Feature flags indicating what the model supports. - [JsonPropertyName("supports")] - public ModelCapabilitiesSupports? Supports { get; set; } + /// What the migration did. Only `migrated` means the persisted settings changed. + [JsonPropertyName("status")] + public StaffUpdateChannelMigrationStatus Status { get; set; } } -/// A service-published message about a model, carrying a stable machine-readable code alongside human-readable text. +/// The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelMessage +internal sealed class UserSettingsHostContext { - /// Stable machine-readable identifier for the message, such as `client_version_deprecated`. Hosts can key custom presentation off this; unrecognized codes should fall back to displaying `message`. - [JsonPropertyName("code")] - public string Code { get; set; } = string.Empty; + /// The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Human-readable message text intended for display to the user. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. + [JsonPropertyName("environment")] + public IDictionary Environment { get => field ??= new Dictionary(); set; } + + /// The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; } -/// Policy state (if applicable). +/// The outcome of the one-time staff model-selection reset. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelPolicy +internal sealed class UserSettingsResetStaffModelSelectionOnceResult { - /// Current policy state for this model. - [JsonPropertyName("state")] - public ModelPolicyState State { get; set; } + /// The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or after it means the reset is already done. + [JsonPropertyName("cutoff")] + public string Cutoff { get; set; } = string.Empty; - /// Usage terms or conditions for this model. - [JsonPropertyName("terms")] - public string? Terms { get; set; } + /// Whether the persisted model selection was cleared. Only `true` means the settings document changed and the host should adopt the returned settings. + [JsonPropertyName("didReset")] + public bool DidReset { get; set; } + + /// The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's own value back unchanged when nothing was reset. + [JsonPropertyName("resetAt")] + public string? ResetAt { get; set; } + + /// The settings document as it stands after the reset, keyed by setting name. Present only when `didReset` is true. + [JsonPropertyName("settings")] + public IDictionary? Settings { get; set; } } -/// A neutral reference to the model provider that produced a model: an opaque id, a human-readable label, and the provider kind. Carried on each enumerated Model so consumers can group by provider without reaching into a provider-shaped internal type. +/// Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderRef +internal sealed class UserSettingsResetStaffModelSelectionOnceRequest { - /// Opaque, stable id of the provider that produced this model. Matches the enumerated `ModelProviderDescriptor.id`. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the reset is evaluated against the server's own home instead. + [JsonPropertyName("context")] + public UserSettingsHostContext Context { get => field ??= new(); set; } - /// The provider kind. - [JsonPropertyName("kind")] - public ModelProviderKind Kind { get; set; } + /// Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. + [JsonPropertyName("staff")] + public bool? Staff { get; set; } - /// Human-readable provider label, owned by the runtime so every consumer renders identical text. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. + [JsonPropertyName("staffModelResetAt")] + public string? StaffModelResetAt { get; set; } } -/// Service-published warning text that hosts should display when presenting a model. +/// The unrecognized top-level keys found in the user settings document, already phrased for display. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelWarningText +internal sealed class UserSettingsUnknownKeysWarningResult { - /// Data-retention warning for the model. The text may contain Markdown links and should be rendered as Markdown when supported. - [JsonPropertyName("dataRetention")] - public string? DataRetention { get; set; } + /// The warning to show the user, naming the unrecognized keys and the file they were found in. Absent when every top-level key is recognized, and also when the document is missing or could not be read, because an unknown-key list taken from a document the runtime could not load would name keys that may not be there. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Copilot model metadata, including identifier, display name, capabilities, policy, billing, reasoning efforts, and picker categories. +/// Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Model +internal sealed class UserSettingsUnknownKeysWarningRequest { - /// Billing information. - [JsonPropertyName("billing")] - public ModelBilling? Billing { get; set; } + /// The configuration directory, home directory and environment to resolve the settings document from. A host that scopes a session to its own Copilot home must pass that directory here, or the server's own home is inspected instead. + [JsonPropertyName("context")] + public UserSettingsHostContext Context { get => field ??= new(); set; } +} - /// Model capabilities and limits. - [JsonPropertyName("capabilities")] - public ModelCapabilities Capabilities { get => field ??= new(); set; } +/// The overrides and host context to resolve effective runtime settings from. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsBuildRuntimeRequest +{ + /// The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. + [JsonPropertyName("environment")] + public IDictionary Environment { get => field ??= new Dictionary(); set; } - /// Default reasoning effort level (only present if model supports reasoning effort). - [JsonPropertyName("defaultReasoningEffort")] - public string? DefaultReasoningEffort { get; set; } + /// Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. + [JsonPropertyName("overrides")] + public IDictionary? Overrides { get; set; } - /// Model identifier (e.g., "claude-sonnet-4.5"). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; - /// Informational notices the service published for this model, such as an upcoming change or a recommended alternative. Present only when the service published at least one notice. Hosts should surface these without implying anything is wrong with the model. - [JsonPropertyName("infoMessages")] - public IList? InfoMessages { get; set; } + /// The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; +} - /// Provider-supplied model metadata. Keys and JSON-compatible values are preserved unchanged. This is factual metadata published by the model provider; it carries no picker or UX semantics. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } +/// The outcome of the one-time staff log-level migration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsMigrateStaffLogLevelOnceResult +{ + /// When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. + [JsonPropertyName("completedAt")] + public string? CompletedAt { get; set; } - /// Model capability category for grouping in the model picker. - [JsonPropertyName("modelPickerCategory")] - public ModelPickerCategory? ModelPickerCategory { get; set; } + /// The settings document as it stands after the migration, keyed by setting name. Present only for `refreshed`, and only when the document could be re-read cleanly. + [JsonPropertyName("settings")] + public IDictionary? Settings { get; set; } - /// Relative cost tier for token-based billing users. - [JsonPropertyName("modelPickerPriceCategory")] - public ModelPickerPriceCategory? ModelPickerPriceCategory { get; set; } + /// What the migration did. Only `refreshed` can have changed the persisted settings. + [JsonPropertyName("status")] + public StaffLogLevelMigrationStatus Status { get; set; } +} - /// Display name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsMigrateStaffLogLevelOnceRequest +{ + /// When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. + [JsonPropertyName("cachedCompletedAt")] + public string? CachedCompletedAt { get; set; } - /// Policy state (if applicable). - [JsonPropertyName("policy")] - public ModelPolicy? Policy { get; set; } + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the migration is evaluated against the server's own home instead. + [JsonPropertyName("context")] + public UserSettingsHostContext Context { get => field ??= new(); set; } +} - /// The model provider that produced this model, as a neutral reference (opaque id, human-readable label, and provider kind). Present on models returned by `session.model.list`, which resolves provider attribution from the session's account roster; absent on the flat `server.models.list`, which does not resolve a session roster. The model picker groups by this reference. - [JsonPropertyName("provider")] - public ModelProviderRef? Provider { get; set; } +/// The outcome of the one-time obsolete-settings cleanup. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsMigrateObsoleteOnDiskResult +{ + /// What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not returned here: the document is written before this replies, so `user.settings.load` reads it authoritatively. + [JsonPropertyName("status")] + public UserSettingsMigrateObsoleteOnDiskStatus Status { get; set; } +} - /// Context-window tiers this model offers, when the provider advertises them independently of tiered token pricing. Copilot models carry their tiers in `billing.tokenPrices`; a provider that has no pricing to publish (an agent host reached over AHP, for example) declares them here instead, so the model picker can still offer the tier toggle. - [JsonPropertyName("supportedContextTiers")] - public IList? SupportedContextTiers { get; set; } +/// Selects the configuration directory whose settings document to clean. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsMigrateObsoleteOnDiskRequest +{ + /// The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } +} - /// Supported reasoning effort levels (only present if model supports reasoning effort). - [JsonPropertyName("supportedReasoningEfforts")] - public IList? SupportedReasoningEfforts { get; set; } +/// A single user setting's effective value alongside its default, so consumers can render settings left at their default. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingMetadata +{ + /// The centrally-known default for this setting (null when no default is registered). + [JsonPropertyName("default")] + public JsonElement Default { get; set; } - /// Warnings the service published for this model, such as a deprecated client version. Present only when the service published at least one warning. The model remains usable; hosts should surface these as advisory rather than blocking. - [JsonPropertyName("warningMessages")] - public IList? WarningMessages { get; set; } + /// True when the user has not set an explicit value for this setting (i.e. it is left at its default). Reflects whether the user has overridden the key, not whether the effective value happens to equal the default — a key explicitly set to a value identical to the default still reports false. + [JsonPropertyName("isDefault")] + public bool IsDefault { get; set; } - /// Warning text the service requires hosts to surface for this model. Present only when the service published at least one warning. - [JsonPropertyName("warningText")] - public ModelWarningText? WarningText { get; set; } + /// The effective value: the user's value if set, otherwise the default. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } } -/// List of Copilot models available to the resolved user, including capabilities and billing metadata. +/// Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelList +public sealed class UserSettingsGetResult { - /// List of available models with full metadata. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// Every known user setting keyed by setting name, each with its effective value, default, and whether it is at the default. + [JsonPropertyName("settings")] + public IDictionary Settings { get => field ??= new Dictionary(); set; } } -/// RPC data type for ModelsList operations. +/// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelsListRequest +internal sealed class UserSettingsGetPathsResult { - /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. - [JsonPropertyName("gitHubToken")] - public string? GitHubToken { get; set; } + /// The repository's local, untracked settings file, or null when no repository root was supplied. + [JsonPropertyName("repoLocalSettings")] + public string? RepoLocalSettings { get; set; } - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// The repository's checked-in settings file, or null when no repository root was supplied. + [JsonPropertyName("repoSettings")] + public string? RepoSettings { get; set; } + + /// The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + [JsonPropertyName("userSettings")] + public string UserSettings { get; set; } = string.Empty; } -/// A well-known model in the runtime's built-in catalog. +/// Selects which settings file paths to resolve. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltInModelCatalogEntry +internal sealed class UserSettingsGetPathsRequest { - /// Well-known runtime model ID suitable for provider or provider-model metadata. This is not necessarily the provider-facing deployment or model name and does not indicate CAPI entitlement or provider availability. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + [JsonPropertyName("repoRoot")] + public string? RepoRoot { get; set; } } -/// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. +/// Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltInModelCatalog +internal sealed class UserSettingsSetRequest { - /// Built-in model entries. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// Partial user settings to write, as a free-form object keyed by setting name. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// Whether this host can run one sandbox policy feature. A session whose effective policy uses an unsupported feature fails each sandboxed command with `reason`, except `filesystem_enumeration`, whose absence degrades sandboxed PowerShell instead of failing it. +/// Top-level user-setting keys grouped by who may govern them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxHostCapability +internal sealed class UserSettingsGovernanceKeysResult { - /// The policy feature, as an extensible string: ignore names you do not recognize. Known values: `network` (sandboxed commands can reach the network; on Linux this needs the tooling for Bubblewrap's private network namespace, such as slirp4netns), `network_filtering` (host rules and the sandbox proxy; on Linux this needs the same tooling as `network`; on Windows it needs Process Security Environment 1.1 host-loopback support, and a policy that uses it must also set `network.allowLocalNetwork`), `denied_paths` (native enforcement of `filesystem.deniedPaths`), `shell` (shell commands inside the sandbox), and `filesystem_enumeration` (enumerate-only filesystem grants; on Windows this needs Process Security Environment 1.1 filesystem enumeration support, and without it sandboxed PowerShell still runs but cannot resolve its current location; other platforms always report it). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Top-level keys a repository may override through a Claude-compatible repository config. + [JsonPropertyName("claudeRepo")] + public IList ClaudeRepo { get => field ??= []; set; } - /// Human-readable reason and remedy when the feature is unsupported, such as a package to install or an OS update. Present only when `supported` is false. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Top-level keys an enterprise policy may fix through managed settings. + [JsonPropertyName("managed")] + public IList Managed { get => field ??= []; set; } - /// Whether this host can run the feature. - [JsonPropertyName("supported")] - public bool Supported { get; set; } + /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. + [JsonPropertyName("repo")] + public IList Repo { get => field ??= []; set; } } -/// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. +/// Outcome of an atomic user or repository settings edit. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxHostSupport +internal sealed class SettingsEditResult { - /// Sandbox policy features whose availability varies between hosts that can run the backend. Empty when `supported` is false, because no feature can run without a backend. Later runtimes can add entries; ignore an entry whose `name` you do not recognize. - [JsonPropertyName("capabilities")] - public IList Capabilities { get => field ??= []; set; } - - /// Human-readable reason the sandbox cannot run on this host. Present only when `supported` is false. - [JsonPropertyName("reason")] - public string? Reason { get; set; } - - /// Whether a process-containment backend is usable on this host: Seatbelt on macOS, Bubblewrap on Linux, or ProcessContainer on Windows. - [JsonPropertyName("supported")] - public bool Supported { get; set; } + /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. + [JsonPropertyName("status")] + public SettingsEditStatus Status { get; set; } } -/// Status of the persistent certificate authority of the sandbox credential proxy. +/// One atomic edit of a canonical setting in settings.json. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxProxyCaStatus +internal sealed class UserSettingsEditRequest { - /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. - [JsonPropertyName("canInstall")] - public bool CanInstall { get; set; } + /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. + [JsonPropertyName("canonicalPath")] + public IList CanonicalPath { get => field ??= []; set; } - /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. - [JsonPropertyName("detail")] - public string? Detail { get; set; } + /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// The state of the certificate authority. - [JsonPropertyName("state")] - public SandboxProxyCaState State { get; set; } + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + [JsonPropertyName("operation")] + public SettingsEditOperation Operation { get; set; } + + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// Credential-injection capability flags applied while the sandbox is enabled. For the same capability independent of sandboxing, and matched to the credential's GitHub host, see `shell.credentials`; the two are additive. +/// Settings object with canonical key names. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigAuth +internal sealed class UserSettingsNormalizeResult { - /// Whether to authenticate sandboxed gh through the local masking proxy. The child receives a fake GH_TOKEN; its real value is substituted only at github.com, api.github.com and uploads.github.com (github.com because gh repo clone authenticates git through gh auth git-credential). The repository's GitHub account takes precedence over the Copilot login. Default: false (opt-in). - [JsonPropertyName("gh")] - public bool? Gh { get; set; } - - /// Whether to authenticate sandboxed HTTPS git through the local masking proxy. The child receives a fake `http.<url>.extraheader`; the real Authorization header is substituted only at its original HTTPS host, port, and repository path scope. github.com uses the Copilot token; other forges use credentials resolved from the user's own helper on the host. Default: false (opt-in). - [JsonPropertyName("git")] - public bool? Git { get; set; } + /// The same settings with every legacy or snake_case key renamed to its canonical spelling. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// Destinations authorized to receive one masked environment credential. +/// Settings object whose key names should be canonicalized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxMaskedEnvVar +internal sealed class UserSettingsNormalizeRequest { - /// Nonempty list of HTTPS injection hostnames or *.example.com patterns. Bare * is not accepted. These grants never override the sandbox network policy. Values in plaintext HTTP requests, URLs, bodies, encoded credentials, and signed requests are not substituted. - [JsonPropertyName("injectHosts")] - public IList InjectHosts { get => field ??= []; set; } + /// Free-form settings object, possibly using legacy or snake_case key names. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// Whole-value environment credential masking for sandboxed children. +/// The settings layer a problem was found in. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxCredentialsConfig +public sealed class UserSettingsProblemLocation { - /// Environment variable names and their HTTPS injection destinations. Absent variables stay absent. No real values or sentinels are stored in this map. - [JsonPropertyName("envVars")] - public IDictionary EnvVars { get => field ??= new Dictionary(); set; } + /// Absolute path of the file backing this layer. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; + + /// Which layer this is: `user`, `repo`, or `local`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// The caller-supplied display label for the layer. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; } -/// macOS seatbelt experimental options. +/// One setting that will not take effect, and why. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyExperimentalSeatbelt +public sealed class UserSettingsProblem { - /// Whether the macOS seatbelt profile may access the keychain. - [JsonPropertyName("keychainAccess")] - public bool? KeychainAccess { get; set; } + /// Coarse grouping for the problem, for a caller that presents problems in sections. + [JsonPropertyName("category")] + public string Category { get; set; } = string.Empty; + + /// Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. + [JsonPropertyName("explanation")] + public string Explanation { get; set; } = string.Empty; + + /// Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// What is wrong in machine-readable form, for a caller that wants to branch rather than display. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. + [JsonPropertyName("rawKey")] + public string? RawKey { get; set; } + + /// The settings layer the problem was found in. + [JsonPropertyName("source")] + public UserSettingsProblemLocation Source { get => field ??= new(); set; } } -/// Platform-specific experimental policy fields. +/// The settings that will not take effect across the given layers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyExperimental +internal sealed class UserSettingsProblemsResult { - /// macOS seatbelt experimental options. - [JsonPropertyName("seatbelt")] - public SandboxConfigUserPolicyExperimentalSeatbelt? Seatbelt { get; set; } + /// Each setting that will not take effect, and why. Empty when every layer is healthy. + [JsonPropertyName("problems")] + public IList? Problems { get; set; } } -/// Filesystem rules to merge into the base policy. +/// One already-loaded settings layer to diagnose. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyFilesystem +public sealed class UserSettingsProblemSource { - /// Whether to clear the policy when the session exits. - [JsonPropertyName("clearPolicyOnExit")] - public bool? ClearPolicyOnExit { get; set; } + /// The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. + [JsonPropertyName("config")] + public IDictionary? Config { get; set; } - /// Paths explicitly denied. - [JsonPropertyName("deniedPaths")] - public IList? DeniedPaths { get; set; } + /// Absolute path of the file backing this layer. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; - /// Paths granted read-only access. - [JsonPropertyName("readonlyPaths")] - public IList? ReadonlyPaths { get; set; } + /// True when the file itself failed to parse, so its keys could not be read at all. + [JsonPropertyName("invalid")] + public bool? Invalid { get; set; } - /// Paths granted read/write access. - [JsonPropertyName("readwritePaths")] - public IList? ReadwritePaths { get; set; } + /// Which layer this is: `user`, `repo`, or `local`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; } -/// HTTP proxy configuration for sandboxed traffic. +/// The settings layers to diagnose. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyNetworkProxy +internal sealed class UserSettingsProblemsRequest { - /// Optional password for proxy authentication, combined with the URL at spawn time. The persisted value may be a literal password, a `${secret:…}` reference resolved from the OS keychain, or a `${VAR}`/`$VAR` environment reference; it is resolved just before the sandboxed process routes through the proxy. The /sandbox dialog stores a real password in the OS keychain and persists only a `${secret:…}` placeholder (never plaintext in settings.json); the field is masked in the dialog and redacted by /settings show. - [JsonPropertyName("password")] - public string? Password { get; set; } - - /// Proxy URL (e.g. http://proxy.example.com:8080). The port is optional and defaults to the scheme's standard port when omitted; an explicit port must be between 1 and 65535. Credentials must not be embedded here — a `user:pass@` authority is rejected; put them in the separate `username`/`password` fields. A credential-free http:// loopback proxy URL is routed through the localhost proxy automatically; loopback covers localhost and any *.localhost subdomain, the whole 127.0.0.0/8 range, ::1, and IPv4-mapped loopback (::ffff:127.0.0.1). An https:// URL, or one with a username/password set, is used as-is. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; + /// Layers to diagnose, in the precedence order the caller applies them. + [JsonPropertyName("sources")] + public IList? Sources { get; set; } +} - /// Optional username for proxy authentication. Combined with the URL (and `password`) into `user:pass@host` when the sandboxed process routes through the proxy. - [JsonPropertyName("username")] - public string? Username { get; set; } +/// One problem found while validating a setting value. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingsValidationIssue +{ + /// Human-readable description of the problem. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. + [JsonPropertyName("path")] + public IList Path { get => field ??= []; set; } } -/// Network rules to merge into the base policy. +/// Outcome of validating and writing one top-level setting subtree. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyNetwork +internal sealed class UserSettingsApplyTopKeyResult { - /// Hosts allowed through the built-in sandbox proxy. A non-empty list denies unmatched hosts; an absent or empty list allows all hosts not blocked. Supports exact hostnames, IP addresses, and *.example.com for strict subdomains. Host rules do not override the outbound or local-network toggles. - [JsonPropertyName("allowedHosts")] - public IList? AllowedHosts { get; set; } + /// Why the write failed, present only when `status` is `write-error`. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Whether traffic to local/loopback addresses is allowed. - [JsonPropertyName("allowLocalNetwork")] - public bool? AllowLocalNetwork { get; set; } + /// Problems found, present only when `status` is `validation-error`. + [JsonPropertyName("issues")] + public IList? Issues { get; set; } - /// Whether outbound network traffic is allowed at all. - [JsonPropertyName("allowOutbound")] - public bool? AllowOutbound { get; set; } + /// `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; +} - /// Hosts denied by the built-in sandbox proxy. Deny rules take precedence over allowedHosts. A domain also denies all its subdomains. IP addresses match exactly; *.example.com matches strict subdomains, and * denies every host. - [JsonPropertyName("blockedHosts")] - public IList? BlockedHosts { get; set; } +/// A single top-level setting subtree to validate and write. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsApplyTopKeyRequest +{ + /// Canonical path of the setting the caller is editing. Currently informational only. + [JsonPropertyName("canonicalPath")] + public IList CanonicalPath { get => field ??= []; set; } - /// HTTP(S) proxy for sandboxed traffic. This is the built-in local proxy's upstream: every sandboxed command reaches it through a loopback listener, so credentials stay in the runtime and never reach the child. On Windows the sandbox also needs local network access, because it reaches that listener over host loopback. Configure credentials in the separate username/password fields. The transient local listener URL is never persisted. - [JsonPropertyName("proxy")] - public SandboxConfigUserPolicyNetworkProxy? Proxy { get; set; } + /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + [JsonPropertyName("completeStaffUpdateChannelMigration")] + public bool? CompleteStaffUpdateChannelMigration { get; set; } + + /// True to remove the top-level key instead of writing it. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } + + /// Top-level setting name to write. + [JsonPropertyName("topKey")] + public string TopKey { get; set; } = string.Empty; + + /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// macOS seatbelt-specific options. +/// The whole content to store in the user settings file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicySeatbelt +internal sealed class UserSettingsWriteAllRequest { - /// Whether the macOS seatbelt profile may access the keychain. - [JsonPropertyName("keychainAccess")] - public bool? KeychainAccess { get; set; } + /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// User-managed sandbox policy fragment merged into the auto-discovered base policy. +/// The stored value of the user setting after the merge. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicy +internal sealed class UserSettingsUpdateResult { - /// Deprecated legacy location for `seatbelt`; read only when the top-level `seatbelt` is absent. - [JsonPropertyName("experimental")] - public SandboxConfigUserPolicyExperimental? Experimental { get; set; } + /// The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } +} - /// Filesystem rules to merge into the base policy. - [JsonPropertyName("filesystem")] - public SandboxConfigUserPolicyFilesystem? Filesystem { get; set; } +/// Names the user setting to merge into, and the partial object to merge. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsUpdateRequest +{ + /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Network rules to merge into the base policy. - [JsonPropertyName("network")] - public SandboxConfigUserPolicyNetwork? Network { get; set; } + /// Top-level user-setting key to merge into, such as `extensions`. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// macOS seatbelt options to merge into the base policy. - [JsonPropertyName("seatbelt")] - public SandboxConfigUserPolicySeatbelt? Seatbelt { get; set; } + /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + [JsonPropertyName("subDir")] + public string? SubDir { get; set; } + + /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } } -/// Resolved sandbox configuration. +/// Contents of settings.json as stored, for a caller about to rewrite it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfig +internal sealed class UserSettingsLoadForEditResult { - /// Whether to auto-add the current working directory to readwritePaths. Default: true. - [JsonPropertyName("addCurrentWorkingDirectory")] - public bool? AddCurrentWorkingDirectory { get; set; } + /// Parsed contents, present only when `status` is `ok`. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } - /// Whether the agent may request that an individual command run outside the sandbox, which the host then approves or denies through the usual permission flow. A host capability flag rather than part of the policy: it is stripped from the effective spawn policy and only has an effect while `enabled` is true. Fail-closed, unlike the opt-out flags on this object: omitting it offers no bypass. Default: false (opt-in). - [JsonPropertyName("allowBypass")] - public bool? AllowBypass { get; set; } + /// `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; +} - /// Whether to auto-grant read access to tool directories discovered on PATH and in toolchain environment variables (GOROOT, JAVA_HOME, VIRTUAL_ENV, and similar), and to common developer-tool caches, config, and toolchains. Writable grants cover scratch caches, the Unix GitHub CLI cache, and Cargo's registry, git store, and lock/tracker files. A relocated CARGO_HOME gets the same narrow split: registry and git are read-write; bin is read-only; the home root, config.toml, and credentials.toml stay ungranted. Set to false to disable every grant listed above; user-installed toolchains and caches then need explicit userPolicy.filesystem readonlyPaths and readwritePaths entries. The working directory (see addCurrentWorkingDirectory), temporary storage, session log paths, and system locations follow their own rules and stay granted. Default: true (enabled by default; set to false to opt out). - [JsonPropertyName("allowDevToolAccess")] - public bool? AllowDevToolAccess { get; set; } +/// Outcome of validating one top-level setting subtree. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsValidateResult +{ + /// Problems found, empty when `ok` is true. + [JsonPropertyName("issues")] + public IList? Issues { get; set; } - /// Credential-injection capability flags. - [JsonPropertyName("auth")] - public SandboxConfigAuth? Auth { get; set; } + /// True when the subtree is valid. + [JsonPropertyName("ok")] + public bool Ok { get; set; } +} - /// Opt-in whole-value environment masking for sandboxed shell, MCP, and LSP children. Configured names get random sentinels; the local proxy substitutes them only in HTTPS request headers at their injection hosts. Approved bypasses skip masking and the sandbox proxy, so bypassed shells may receive the real environment values. Disabled or explicitly opted-out routes are not protected. No credential values are stored in this configuration. - [JsonPropertyName("credentials")] - public SandboxCredentialsConfig? Credentials { get; set; } +/// A single top-level setting subtree to validate. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsValidateRequest +{ + /// True to validate a removal of this key. The current settings file is not read. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } - /// Whether sandboxing is enabled for the session. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Top-level setting name to validate. + [JsonPropertyName("topKey")] + public string TopKey { get; set; } = string.Empty; - /// The `sandboxLspServers` counterpart of `managedMcpRoutingLocked`. - [JsonInclude] - [JsonPropertyName("managedLspRoutingLocked")] - internal bool? ManagedLspRoutingLocked { get; set; } + /// Value to validate. Omitted when `delete` is true. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} - /// Set by the runtime when a managed policy forced `sandboxMcpServers` on and took the local opt-out away. Provenance rather than policy: it lets a sandbox startup failure point at the administrator instead of a setting the next managed merge would override, and it is ignored when comparing two configs for change. Only the managed merge may set it; a caller-supplied value is stripped. - [JsonInclude] - [JsonPropertyName("managedMcpRoutingLocked")] - internal bool? ManagedMcpRoutingLocked { get; set; } +/// One atomic edit of an allowed top-level repository setting. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsEditRequest +{ + /// One canonical top-level repository setting that the allowlist permits. + [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("key")] + public string Key { get; set; } = string.Empty; - /// Whether language servers the session launches are confined by the sandbox. Only an explicit `false` opts out. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). - [JsonPropertyName("sandboxLspServers")] - public bool? SandboxLspServers { get; set; } + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + [JsonPropertyName("operation")] + public SettingsEditOperation Operation { get; set; } - /// Whether MCP servers the session launches are confined by the sandbox. Only an explicit `false` opts out; doing so also lets remote-MCP egress leave the sandbox, so the flag and `enabled` are always read together. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). - [JsonPropertyName("sandboxMcpServers")] - public bool? SandboxMcpServers { get; set; } + /// Absolute path of the repository root. + [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("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// User-managed sandbox policy fragment merged into the auto-discovered base policy. - [JsonPropertyName("userPolicy")] - public SandboxConfigUserPolicy? UserPolicy { get; set; } + /// Shared or local repository settings file. + [JsonPropertyName("scope")] + public RepoSettingsEditScope Scope { get; set; } + + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. +/// Parsed repository settings without normalization or layering. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SandboxProxyCaRequest +internal sealed class RepoSettingsReadRawResult { - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - [JsonPropertyName("sandboxConfig")] - public SandboxConfig? SandboxConfig { get; set; } + /// Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. + [JsonPropertyName("config")] + public JsonElement Config { get; set; } + + /// True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. + [JsonPropertyName("invalid")] + public bool Invalid { get; set; } } -/// Result of creating the persistent certificate authority of the sandbox credential proxy. +/// Which repository settings file to read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxProxyCaCreateResult +internal sealed class RepoSettingsReadRawRequest { - /// Absolute path of the public certificate of the certificate authority, in PEM format. - [JsonPropertyName("certificatePath")] - public string CertificatePath { get; set; } = string.Empty; + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; + + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; } -/// Built-in tool metadata with identifier, optional namespaced name, description, input-parameter schema, and usage instructions. +/// One key to write or remove in a repository settings file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Tool +internal sealed class RepoSettingsWriteKeyRequest { - /// Description of what the tool does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Optional instructions for how to use this tool effectively. - [JsonPropertyName("instructions")] - public string? Instructions { get; set; } + /// True to remove the key instead of writing it. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } - /// Tool identifier (e.g., "bash", "grep", "str_replace_editor"). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Canonical top-level key permitted by the repository settings allowlist. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools). - [JsonPropertyName("namespacedName")] - public string? NamespacedName { get; set; } + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// JSON Schema for the tool's input parameters. - [JsonPropertyName("parameters")] - public IDictionary? Parameters { get; set; } + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; - /// Telemetry-safety policy for the tool name and input names, not input values. Treat omitted metadata as unsafe. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("safeForTelemetry")] - public JsonElement? SafeForTelemetry { get; set; } + /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// Built-in tools available for the requested model, with their parameters and instructions. +/// The complete set of repository-overridable settings to store. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolList +internal sealed class RepoSettingsWriteAllRequest { - /// List of available built-in tools with metadata. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } -} + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; -/// Optional model identifier whose tool overrides should be applied to the listing. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsListRequest -{ - /// Optional model ID — when provided, the returned tool list reflects model-specific overrides. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; + + /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// Quota usage snapshot for a Copilot quota type, including entitlement, used requests, overage, reset date, and remaining percentage. +/// Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountQuotaSnapshot +internal sealed class FeatureFlagsResolveStartupGatesRequest { - /// Number of requests included in the entitlement, or -1 for unlimited entitlements. - [JsonPropertyName("entitlementRequests")] - public long EntitlementRequests { get; set; } + /// User settings document whose `featureFlags` block is layered on top of the resolved set. + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// Whether the user has an unlimited usage entitlement. - [JsonPropertyName("isUnlimitedEntitlement")] - public bool IsUnlimitedEntitlement { get; set; } + /// Environment to read flag overrides from. Defaults to this runtime process's own environment. + [JsonPropertyName("environment")] + public IDictionary? Environment { get; set; } - /// Number of additional usage requests made this period. - [JsonPropertyName("overage")] - public double Overage { get; set; } + /// When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. + [JsonPropertyName("firstLaunchAtMillis")] + public double? FirstLaunchAtMillis { get; set; } - /// Whether additional usage is allowed when quota is exhausted. - [JsonPropertyName("overageAllowedWithExhaustedQuota")] - public bool OverageAllowedWithExhaustedQuota { get; set; } + /// The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. + [JsonPropertyName("flags")] + public IList Flags { get => field ??= []; set; } - /// Percentage of entitlement remaining. - [JsonPropertyName("remainingPercentage")] - public double RemainingPercentage { get; set; } + /// Whether the caller is in an experimental population. + [JsonPropertyName("isExperimental")] + public bool IsExperimental { get; set; } - /// Date when the quota resets (ISO 8601 string). - [JsonPropertyName("resetDate")] - public DateTimeOffset? ResetDate { get; set; } + /// Whether the caller is GitHub or Microsoft staff. + [JsonPropertyName("isStaff")] + public bool IsStaff { get; set; } - /// Whether usage is still permitted after quota exhaustion. - [JsonPropertyName("usageAllowedWithExhaustedQuota")] - public bool UsageAllowedWithExhaustedQuota { get; set; } + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + [JsonPropertyName("isStaffGithub")] + public bool? IsStaffGitHub { get; set; } - /// Number of requests used so far this period. - [JsonPropertyName("usedRequests")] - public long UsedRequests { get; set; } -} + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + [JsonPropertyName("isStaffMicrosoft")] + public bool? IsStaffMicrosoft { get; set; } -/// Quota usage snapshots for the resolved user, keyed by quota type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountGetQuotaResult -{ - /// Quota snapshots keyed by type (e.g., chat, completions, premium_interactions). - [JsonPropertyName("quotaSnapshots")] - public IDictionary QuotaSnapshots { get => field ??= new Dictionary(); set; } + /// Whether the caller belongs to a team plan. + [JsonPropertyName("isTeam")] + public bool IsTeam { get; set; } + + /// Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. + [JsonPropertyName("refreshWithoutSession")] + public bool RefreshWithoutSession { get; set; } + + /// Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. + [JsonPropertyName("streamerMode")] + public bool StreamerMode { get; set; } } -/// RPC data type for AccountGetQuota operations. +/// The declared shape of one feature flag, independent of any caller population. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountGetQuotaRequest +internal sealed class FeatureFlagMetadata { - /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. - [JsonPropertyName("gitHubToken")] - public string? GitHubToken { get; set; } + /// The population the flag is declared for before any environment or user-settings override is applied. + [JsonPropertyName("availability")] + public FeatureFlagAvailability Availability { get; set; } - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// Whether the flag participates in the CAPI sanity suite. + [JsonPropertyName("capiSanity")] + public bool CapiSanity { get; set; } + + /// Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. + [JsonPropertyName("experimentalDescription")] + public string? ExperimentalDescription { get; set; } + + /// The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. + [JsonPropertyName("expFlag")] + public string? ExpFlag { get; set; } + + /// Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. + [JsonPropertyName("expFlagEnvVar")] + public string? ExpFlagEnvVar { get; set; } + + /// The flag's name, matching the key it is listed under. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Authentication credentials accepted only at native protocol ingress. Runtime outputs use credential-free `AuthIdentity` metadata. -/// Polymorphic base type discriminated by type. +/// Every feature flag this runtime declares, with the shape each one was declared with. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthInfoHmac), "hmac")] -[JsonDerivedType(typeof(AuthInfoEnv), "env")] -[JsonDerivedType(typeof(AuthInfoToken), "token")] -[JsonDerivedType(typeof(AuthInfoTokenProvider), "token-provider")] -[JsonDerivedType(typeof(AuthInfoCopilotApiToken), "copilot-api-token")] -[JsonDerivedType(typeof(AuthInfoUser), "user")] -[JsonDerivedType(typeof(AuthInfoGhCli), "gh-cli")] -[JsonDerivedType(typeof(AuthInfoApiKey), "api-key")] -public partial class AuthInfo +internal sealed class FeatureFlagsMetadataResult { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + /// Declared feature flags keyed by flag name. + [JsonPropertyName("flags")] + public IDictionary Flags { get => field ??= new Dictionary(); set; } } - -/// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. +/// Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseEndpoints +internal sealed class FeatureFlagsResolveRequest { - /// Copilot API endpoint URL. - [JsonPropertyName("api")] - public string? Api { get; set; } + /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + [JsonPropertyName("baseFlags")] + public IDictionary? BaseFlags { get; set; } - /// Experimental-service endpoint URL. - [JsonPropertyName("exp")] - public string? Exp { get; set; } + /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// Origin-tracker endpoint URL. - [JsonPropertyName("origin-tracker")] - public string? OriginTracker { get; set; } + /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + [JsonPropertyName("environment")] + public IDictionary? Environment { get; set; } - /// Copilot proxy endpoint URL. - [JsonPropertyName("proxy")] - public string? Proxy { get; set; } + /// Flags forced to a value after every other layer, keyed by flag name. + [JsonPropertyName("flagOverrides")] + public IDictionary? FlagOverrides { get; set; } - /// Copilot telemetry endpoint URL. - [JsonPropertyName("telemetry")] - public string? Telemetry { get; set; } + /// Whether the caller is in an experimental population. + [JsonPropertyName("isExperimental")] + public bool IsExperimental { get; set; } + + /// Whether the caller is GitHub or Microsoft staff. + [JsonPropertyName("isStaff")] + public bool IsStaff { get; set; } + + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + [JsonPropertyName("isStaffGithub")] + public bool? IsStaffGitHub { get; set; } + + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + [JsonPropertyName("isStaffMicrosoft")] + public bool? IsStaffMicrosoft { get; set; } + + /// Whether the caller belongs to the team population used by feature availability. + [JsonPropertyName("isTeam")] + public bool IsTeam { get; set; } } -/// RPC data type for CopilotUserResponseEnterpriseListItem operations. -public sealed class CopilotUserResponseEnterpriseListItem +/// The policy questions a host asks before granting elevated permissions. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionsEvaluateManagedPolicyResult { - /// JavaScript-safe numeric database ID of the enterprise. - [JsonPropertyName("id")] - public long? Id { get; set; } + /// True when managed policy forbids bypass-permissions mode, so allow-all style flags must not take effect. + [JsonPropertyName("bypassPermissionsDisabled")] + public bool BypassPermissionsDisabled { get; set; } + + /// True when the managed layer supplies permission rules that the session must enforce. + [JsonPropertyName("permissionRulesActive")] + public bool PermissionRulesActive { get; set; } + + /// True when a managed policy exists but this build could not determine its meaning. Hosts fail closed on it rather than assuming permission was granted. + [JsonPropertyName("policyUndetermined")] + public bool PolicyUndetermined { get; set; } } -/// RPC data type for CopilotUserResponseOrganizationListItem operations. -public sealed class CopilotUserResponseOrganizationListItem +/// The verbatim managed `permissions` slice to interpret. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionsEvaluateManagedPolicyParams { - /// Numeric database ID of the organization. - [JsonPropertyName("id")] - public double? Id { get; set; } + /// The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. + [JsonPropertyName("permissions")] + public JsonElement? Permissions { get; set; } +} - /// GitHub login of the organization. - [JsonPropertyName("login")] - public string? Login { get; set; } +/// Which stored location permissions were dropped because their directory is gone. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class LocationPermissionsCleanupResult +{ + /// Location keys whose grants were removed. Empty when every stored location still exists. + [JsonPropertyName("removedLocationKeys")] + public IList RemovedLocationKeys { get => field ??= []; set; } +} - /// Display name of the organization. - [JsonPropertyName("name")] - public string? Name { get; set; } +/// Folder trust check result. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class FolderTrustCheckResult +{ + /// Whether the folder is trusted. + [JsonPropertyName("trusted")] + public bool Trusted { get; set; } } -/// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. +/// A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshotsChat +internal sealed class FolderTrustIsTrustedParams { - /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. - [JsonPropertyName("entitlement")] - public double? Entitlement { get; set; } + /// Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. - [JsonPropertyName("has_quota")] - public bool? HasQuota { get; set; } + /// Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} - /// Count of additional pay-per-request usage consumed this period beyond the entitlement. - [JsonPropertyName("overage_count")] - public double? OverageCount { get; set; } +/// The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsReadDeviceResult +{ + /// Whether discovery or validation failed. A host must treat this as "policy unknown" rather than "no policy": absent settings with this set false mean the device genuinely has none. + [JsonPropertyName("loadFailed")] + public bool LoadFailed { get; set; } - /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. - [JsonPropertyName("overage_permitted")] - public bool? OveragePermitted { get; set; } + /// Sandbox floor read from the discovered document before validation, so a document that is otherwise rejected can still raise the floor it declared. + [JsonPropertyName("sandboxFloor")] + public JsonElement? SandboxFloor { get; set; } - /// Percentage of the entitlement remaining at the snapshot timestamp. - [JsonPropertyName("percent_remaining")] - public double? PercentRemaining { get; set; } + /// Validated, canonical device-managed settings. Omitted when no device policy was discovered, when the discovered document failed validation, or when it validated to an empty object — an empty document carries no policy, and reporting it as present would outrank layers that do. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } +} - /// Identifier of the quota bucket this snapshot describes. - [JsonPropertyName("quota_id")] - public string? QuotaId { get; set; } +/// The managed layers to retain as this process's startup policy, with the outcome of fetching each one. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsRetainPolicyParams +{ + /// Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. + [JsonPropertyName("deviceLoadFailed")] + public bool DeviceLoadFailed { get; set; } - /// Amount of quota remaining at the snapshot timestamp. - [JsonPropertyName("quota_remaining")] - public double? QuotaRemaining { get; set; } + /// The device/MDM policy layer. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } - /// Unix epoch time, in seconds, when this quota next resets. - [JsonPropertyName("quota_reset_at")] - public double? QuotaResetAt { get; set; } + /// Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } - /// Remaining entitlement/quota amount at the snapshot timestamp. - [JsonPropertyName("remaining")] - public double? Remaining { get; set; } + /// Whether the device sandbox intent is unreadable independently of its other settings. + [JsonPropertyName("deviceSandboxUndetermined")] + public bool DeviceSandboxUndetermined { get; set; } - /// UTC timestamp when this snapshot was captured. - [JsonPropertyName("timestamp_utc")] - public string? TimestampUtc { get; set; } + /// Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. + [JsonPropertyName("deviceSourceFound")] + public bool DeviceSourceFound { get; set; } - /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } + /// Whether any managed policy source exists, independently of fetch failures. + [JsonPropertyName("managedPolicyPresent")] + public bool ManagedPolicyPresent { get; set; } - /// Whether the entitlement for this category is unlimited. - [JsonPropertyName("unlimited")] - public bool? Unlimited { get; set; } -} + /// Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. + [JsonPropertyName("permissionPolicyUndetermined")] + public bool PermissionPolicyUndetermined { get; set; } -/// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshotsCompletions -{ - /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. - [JsonPropertyName("entitlement")] - public double? Entitlement { get; set; } + /// The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. + [JsonPropertyName("policyHelperResponse")] + public JsonElement? PolicyHelperResponse { get; set; } - /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. - [JsonPropertyName("has_quota")] - public bool? HasQuota { get; set; } + /// Preserve the retained server layer during a device-only resolution. + [JsonPropertyName("preserveServerState")] + public bool PreserveServerState { get; set; } - /// Count of additional pay-per-request usage consumed this period beyond the entitlement. - [JsonPropertyName("overage_count")] - public double? OverageCount { get; set; } + /// Whether uncertainty alone enabled the shared sandbox floor. + [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] + public bool SandboxEnabledByUndeterminedPolicy { get; set; } - /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. - [JsonPropertyName("overage_permitted")] - public bool? OveragePermitted { get; set; } + /// Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. + [JsonPropertyName("sandboxFloorUndetermined")] + public bool SandboxFloorUndetermined { get; set; } - /// Percentage of the entitlement remaining at the snapshot timestamp. - [JsonPropertyName("percent_remaining")] - public double? PercentRemaining { get; set; } + /// Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. + [JsonPropertyName("serverFetchFailed")] + public bool ServerFetchFailed { get; set; } - /// Identifier of the quota bucket this snapshot describes. - [JsonPropertyName("quota_id")] - public string? QuotaId { get; set; } + /// Whether a required fresh server-policy confirmation failed. + [JsonPropertyName("serverForcedRefreshFailure")] + public bool ServerForcedRefreshFailure { get; set; } - /// Amount of quota remaining at the snapshot timestamp. - [JsonPropertyName("quota_remaining")] - public double? QuotaRemaining { get; set; } + /// The resolved server policy. A known source can lack a response after a forced-refresh failure. + [JsonPropertyName("serverResponse")] + public JsonElement? ServerResponse { get; set; } - /// Unix epoch time, in seconds, when this quota next resets. - [JsonPropertyName("quota_reset_at")] - public double? QuotaResetAt { get; set; } + /// Whether the server policy source exists, even when its response is unavailable. + [JsonPropertyName("serverSourceFound")] + public bool ServerSourceFound { get; set; } - /// Remaining entitlement/quota amount at the snapshot timestamp. - [JsonPropertyName("remaining")] - public double? Remaining { get; set; } + /// Shared server/device sandbox floor, excluding session-local helper policy. + [JsonPropertyName("sharedSandboxFloor")] + public JsonElement? SharedSandboxFloor { get; set; } +} - /// UTC timestamp when this snapshot was captured. - [JsonPropertyName("timestamp_utc")] - public string? TimestampUtc { get; set; } +/// The user settings with the managed layer's controlled entries stamped on. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsApplyControlsResult +{ + /// The resulting settings document. + [JsonPropertyName("settingsJson")] + public JsonElement SettingsJson { get; set; } +} - /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } +/// A user settings document and the effective managed policy whose controlled entries should be stamped onto it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsApplyControlsParams +{ + /// The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. + [JsonPropertyName("managed")] + public JsonElement? Managed { get; set; } - /// Whether the entitlement for this category is unlimited. - [JsonPropertyName("unlimited")] - public bool? Unlimited { get; set; } + /// The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. +/// The accepted managed settings, reduced to the keys a client is allowed to set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshotsPremiumInteractions +internal sealed class ManagedSettingsParseClientValueResult { - /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. - [JsonPropertyName("entitlement")] - public double? Entitlement { get; set; } - - /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. - [JsonPropertyName("has_quota")] - public bool? HasQuota { get; set; } + /// The normalized settings. Omitted when the client supplied none. An accepted document that sets nothing comes back as an empty object, which is distinct from omission. + [JsonPropertyName("settingsJson")] + public JsonElement? SettingsJson { get; set; } +} - /// Count of additional pay-per-request usage consumed this period beyond the entitlement. - [JsonPropertyName("overage_count")] - public double? OverageCount { get; set; } +/// The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsParseClientValueParams +{ + /// The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } +} - /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. - [JsonPropertyName("overage_permitted")] - public bool? OveragePermitted { get; set; } +/// The effective managed policy composed from the supplied layers. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsResolveEffectiveValueResult +{ + /// The composed effective managed settings. Omitted when no layer sets anything, so an unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an advisory server force-on was dropped because this host cannot run the sandbox. + [JsonPropertyName("settingsJson")] + public JsonElement? SettingsJson { get; set; } +} - /// Percentage of the entitlement remaining at the snapshot timestamp. - [JsonPropertyName("percent_remaining")] - public double? PercentRemaining { get; set; } +/// The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsResolveEffectiveValueParams +{ + /// The device sandbox floor, folded into the device layer under `sandbox` before composition. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } - /// Identifier of the quota bucket this snapshot describes. - [JsonPropertyName("quota_id")] - public string? QuotaId { get; set; } + /// The device layer: native MDM and managed-file settings describing the machine rather than the account. + [JsonPropertyName("mdm")] + public JsonElement? Mdm { get; set; } - /// Amount of quota remaining at the snapshot timestamp. - [JsonPropertyName("quota_remaining")] - public double? QuotaRemaining { get; set; } + /// The policy-helper layer, an enforced channel sourced from a platform policy helper process. + [JsonPropertyName("policyHelper")] + public JsonElement? PolicyHelper { get; set; } - /// Unix epoch time, in seconds, when this quota next resets. - [JsonPropertyName("quota_reset_at")] - public double? QuotaResetAt { get; set; } + /// The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. + [JsonPropertyName("server")] + public JsonElement? Server { get; set; } +} - /// Remaining entitlement/quota amount at the snapshot timestamp. - [JsonPropertyName("remaining")] - public double? Remaining { get; set; } +/// The bypass-permissions state a host should hold after the resolution, and what it must do to get there. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsResolveBypassDisableTransitionResult +{ + /// The account the returned `managed` source is pinned to. Store it alongside `source`; the next call needs it to decide whether an account switch lifts the disable. + [JsonPropertyName("managedIdentity")] + public string? ManagedIdentity { get; set; } - /// UTC timestamp when this snapshot was captured. - [JsonPropertyName("timestamp_utc")] - public string? TimestampUtc { get; set; } + /// The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly as it is, which is not the same as being told to store `false`. + [JsonPropertyName("setDisabledState")] + public bool? SetDisabledState { get; set; } - /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } + /// Which layer disables bypass mode after this resolution. Omitted when none does, which is what a lifted disable looks like. + [JsonPropertyName("source")] + public ManagedSettingsBypassDisableSource? Source { get; set; } - /// Whether the entitlement for this category is unlimited. - [JsonPropertyName("unlimited")] - public bool? Unlimited { get; set; } + /// Whether a bypass-permissions session already running must be turned off. True only when this resolution newly disables bypass mode, so a host that is already compliant is not interrupted. + [JsonPropertyName("suppressRuntimeAllowAll")] + public bool SuppressRuntimeAllowAll { get; set; } } -/// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. +/// The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshots +internal sealed class ManagedSettingsResolveBypassDisableTransitionParams { - /// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. - [JsonPropertyName("chat")] - public CopilotUserResponseQuotaSnapshotsChat? Chat { get; set; } + /// The account signed in now. A `managed` disable pinned to a different account is lifted. + [JsonPropertyName("activeIdentity")] + public string ActiveIdentity { get; set; } = string.Empty; - /// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. - [JsonPropertyName("completions")] - public CopilotUserResponseQuotaSnapshotsCompletions? Completions { get; set; } + /// The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. + [JsonPropertyName("currentManagedIdentity")] + public string? CurrentManagedIdentity { get; set; } - /// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. - [JsonPropertyName("premium_interactions")] - public CopilotUserResponseQuotaSnapshotsPremiumInteractions? PremiumInteractions { get; set; } + /// Which layer currently disables bypass mode. Omit it when nothing does. + [JsonPropertyName("currentSource")] + public ManagedSettingsBypassDisableSource? CurrentSource { get; set; } + + /// What the resolution said about bypass mode. Send `unknown` rather than omitting the field when there is no verdict. + [JsonPropertyName("policy")] + public ManagedSettingsBypassPolicyResolution Policy { get; set; } } -/// 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. +/// One diagnostic emitted while ingesting managed settings. Returned rather than logged by the runtime so the host decides where ingestion diagnostics go, which matters because an ingestion runs before a session exists to carry a log sink. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponse +internal sealed class ManagedSettingsLogMessage { - /// Copilot access SKU identifier (e.g. `free_limited_copilot`, `copilot_for_business_seat_quota`) used to gate model and feature access. - [JsonPropertyName("access_type_sku")] - public string? AccessTypeSku { get; set; } + /// Severity of this diagnostic. + [JsonPropertyName("level")] + public ManagedSettingsLogLevel Level { get; set; } - /// Opaque analytics tracking identifier for the user, forwarded from the Copilot API. - [JsonPropertyName("analytics_tracking_id")] - public string? AnalyticsTrackingId { get; set; } + /// Human-readable diagnostic text. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; +} - /// Date the Copilot seat was assigned to the user, if applicable. - [JsonPropertyName("assigned_date")] - public string? AssignedDate { get; set; } +/// The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsIngestResult +{ + /// The device layer could not be read, so it is unconfirmed rather than known-absent. + [JsonPropertyName("deviceLoadFailed")] + public bool DeviceLoadFailed { get; set; } - /// Whether the user is eligible to sign up for the free/limited Copilot tier. - [JsonPropertyName("can_signup_for_limited")] - public bool? CanSignupForLimited { get; set; } + /// The device layer discovered from the machine, when one exists. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } - /// Whether the user is able to upgrade their Copilot plan. - [JsonPropertyName("can_upgrade_plan")] - public bool? CanUpgradePlan { get; set; } + /// The sandbox floor contributed by the device layer. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } - /// Whether Copilot chat is enabled for the user. - [JsonPropertyName("chat_enabled")] - public bool? ChatEnabled { get; set; } + /// Whether the device layer's sandbox intent could not be determined, so a consumer must not read its absence as permission to run unsandboxed. + [JsonPropertyName("deviceSandboxUndetermined")] + public bool DeviceSandboxUndetermined { get; set; } - /// Whether CLI remote control is enabled for the user. - [JsonPropertyName("cli_remote_control_enabled")] - public bool? CliRemoteControlEnabled { get; set; } + /// A device-managed policy is known to exist. + [JsonPropertyName("deviceSourceFound")] + public bool DeviceSourceFound { get; set; } - /// Whether cloud session storage is enabled for the user. - [JsonPropertyName("cloud_session_storage_enabled")] - public bool? CloudSessionStorageEnabled { get; set; } + /// Diagnostics emitted while resolving the layers, in the order they occurred. + [JsonPropertyName("logMessages")] + public IList LogMessages { get => field ??= []; set; } - /// Whether the Codex agent is enabled for the user. - [JsonPropertyName("codex_agent_enabled")] - public bool? CodexAgentEnabled { get; set; } + /// The effective managed permissions layer, when the resolved policy carries one. + [JsonPropertyName("permissions")] + public JsonElement? Permissions { get; set; } - /// Copilot plan name for the user (e.g. `individual`, `business`, `enterprise`). - [JsonPropertyName("copilot_plan")] - public string? CopilotPlan { get; set; } + /// Which channel registered the policy helper that produced the helper layer. + [JsonPropertyName("policyHelperAuthority")] + public ManagedSettingsPolicyHelperAuthority? PolicyHelperAuthority { get; set; } - /// Whether `.copilotignore` content-exclusion support is enabled for the user. - [JsonPropertyName("copilotignore_enabled")] - public bool? CopilotignoreEnabled { get; set; } + /// A policy helper is configured for this host. + [JsonPropertyName("policyHelperConfigured")] + public bool PolicyHelperConfigured { get; set; } - /// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. - [JsonPropertyName("endpoints")] - public CopilotUserResponseEndpoints? Endpoints { get; set; } + /// The policy helper's failure must be treated as fail-closed rather than ignored. + [JsonPropertyName("policyHelperFailClosed")] + public bool PolicyHelperFailClosed { get; set; } - /// Enterprises that provide the user's Copilot license; malformed entries are normalized to null or ID-less shapes. - [JsonPropertyName("enterprise_list")] - public IList? EnterpriseList { get; set; } + /// The policy helper was configured but could not be run or its output could not be read. + [JsonPropertyName("policyHelperLoadFailed")] + public bool PolicyHelperLoadFailed { get; set; } - /// Whether MCP (Model Context Protocol) support is enabled for the user. - [JsonPropertyName("is_mcp_enabled")] - public bool? IsMcpEnabled { get; set; } + /// The layer produced by the platform policy helper, when one ran. + [JsonPropertyName("policyHelperResponse")] + public JsonElement? PolicyHelperResponse { get; set; } - /// Whether the user is a GitHub/Microsoft staff member. - [JsonPropertyName("is_staff")] - public bool? IsStaff { get; set; } + /// A live fetch failed but a recent cached entry was served in its place, so `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a cache-backed fallback. + [JsonPropertyName("serverCacheFallback")] + public bool ServerCacheFallback { get; set; } - /// Per-category quota allotments for free/limited-tier users, keyed by quota category. - [JsonPropertyName("limited_user_quotas")] - public IDictionary? LimitedUserQuotas { get; set; } + /// Minimum client version requested by a successful response. Advisory only; the delivered policy remains active. + [JsonPropertyName("serverClientUpdateRequested")] + public string? ServerClientUpdateRequested { get; set; } - /// Date the free/limited-tier user's quotas next reset, as a raw string from the Copilot API. - [JsonPropertyName("limited_user_reset_date")] - public string? LimitedUserResetDate { get; set; } + /// The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. Gates that exist only because of managed policy should deny on this rather than falling back to their unmanaged default. + [JsonPropertyName("serverClientUpdateRequired")] + public string? ServerClientUpdateRequired { get; set; } - /// GitHub login of the authenticated user. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// The error that made the server fetch fail, when one did. + [JsonPropertyName("serverFetchError")] + public string? ServerFetchError { get; set; } - /// Per-category monthly quota allotments, keyed by quota category. - [JsonPropertyName("monthly_quotas")] - public IDictionary? MonthlyQuotas { get; set; } + /// The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. + [JsonPropertyName("serverFetchFailed")] + public bool ServerFetchFailed { get; set; } - /// Organizations the user belongs to, each with an optional ID, login, and display name. - [JsonPropertyName("organization_list")] - public IList? OrganizationList { get; set; } + /// The server fetch failed while a policy demanded a fresh confirmation, which is the strict posture an enterprise opted into rather than an ordinary transient failure. + [JsonPropertyName("serverForcedRefreshFailure")] + public bool ServerForcedRefreshFailure { get; set; } - /// Logins of the organizations the user belongs to. - [JsonPropertyName("organization_login_list")] - public IList? OrganizationLoginList { get; set; } + /// The synthesized fail-closed permissions layer applied in place of a policy a refused client may not enforce. + [JsonPropertyName("serverPermissionsFloor")] + public JsonElement? ServerPermissionsFloor { get; set; } - /// Date the user's usage quota next resets, as a raw string from the Copilot API; see `quota_reset_date_utc` for the UTC-normalized value. - [JsonPropertyName("quota_reset_date")] - public string? QuotaResetDate { get; set; } + /// How the server layer was resolved. + [JsonPropertyName("serverResolution")] + public ManagedSettingsServerPolicyResolution ServerResolution { get; set; } - /// UTC-normalized form of `quota_reset_date` (the date the user's usage quota next resets). - [JsonPropertyName("quota_reset_date_utc")] - public string? QuotaResetDateUtc { get; set; } + /// The account's server-delivered policy, when one was resolved. + [JsonPropertyName("serverResponse")] + public JsonElement? ServerResponse { get; set; } - /// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. - [JsonPropertyName("quota_snapshots")] - public CopilotUserResponseQuotaSnapshots? QuotaSnapshots { get; set; } + /// The server fetch failed in a way a later retry could succeed at, as opposed to a refusal that no retry will change. + [JsonPropertyName("serverRetryableFailure")] + public bool ServerRetryableFailure { get; set; } - /// Whether the user's telemetry is subject to restricted-data handling. - [JsonPropertyName("restricted_telemetry")] - public bool? RestrictedTelemetry { get; set; } + /// The sandbox object from a cached server policy that a forced refresh declined to serve in full. Folded back into the effective sandbox layer so an outage during a forced refresh still synthesizes the fail-closed sandbox floor from the administrator's known intent. + [JsonPropertyName("serverSandboxFloor")] + public JsonElement? ServerSandboxFloor { get; set; } - /// Raw passthrough of the Copilot API `te` flag for the user (an opaque server-side eligibility signal surfaced in telemetry); not otherwise interpreted by the runtime. - [JsonPropertyName("te")] - public bool? Te { get; set; } + /// A server-managed policy is known to exist even though `serverResponse` is intentionally unset. Consumers should OR this with the presence of `serverResponse` when deciding whether the device is managed, so a fresh start during an outage still applies the fail-closed gates instead of treating the device as unmanaged. + [JsonPropertyName("serverSourceFound")] + public bool ServerSourceFound { get; set; } - /// Whether the account is on usage-based (token/AI-credit) billing rather than a fixed premium-request quota. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } + /// No usable token was available, so no server fetch was attempted. + [JsonPropertyName("serverTokenUnavailable")] + public bool ServerTokenUnavailable { get; set; } + + /// The effective managed settings composed from every resolved layer. Omitted when no layer set anything, so an unmanaged host locks nothing. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } } -/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. -/// The hmac variant of . +/// Inputs describing the host and account an ingestion should resolve managed policy for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoHmac : AuthInfo +internal sealed class ManagedSettingsIngestParams { - /// - [JsonIgnore] - public override string Type => "hmac"; + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + [JsonPropertyName("authInfo")] + public JsonElement? AuthInfo { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + [JsonPropertyName("bypassCacheRead")] + public bool? BypassCacheRead { get; set; } - /// HMAC secret used to sign requests. - [JsonPropertyName("hmac")] - public required string Hmac { get; set; } + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// Authentication host. HMAC auth always targets the public GitHub host. - [JsonPropertyName("host")] - public required string Host { get; set; } -} + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } -/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. -/// The env variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoEnv : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "env"; + /// The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + [JsonPropertyName("hasDeviceResponse")] + public bool? HasDeviceResponse { get; set; } - /// Name of the environment variable the token was sourced from. - [JsonPropertyName("envVar")] - public required string EnvVar { get; set; } + /// The host's home directory, used to resolve cache and managed-file locations. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; - /// Authentication host (e.g. https://github.com or a GHES host). - [JsonPropertyName("host")] - public required string Host { get; set; } + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; - /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + [JsonPropertyName("policyHelperEnabled")] + public bool? PolicyHelperEnabled { get; set; } - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } -} + /// The policy-helper invocation reason. Defaults to sessionStart. + [JsonPropertyName("policyHelperReason")] + public ManagedSettingsPolicyHelperReason? PolicyHelperReason { get; set; } -/// Authentication-info input variant for SDK-configured token authentication, carrying host and the secret token value. -/// The token variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoToken : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "token"; + /// Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + [JsonPropertyName("policyHelperWorkingDirectory")] + public string? PolicyHelperWorkingDirectory { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + [JsonPropertyName("selfFetch")] + public bool? SelfFetch { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. + [JsonPropertyName("serverPolicyCacheMode")] + public ManagedSettingsServerPolicyCacheMode? ServerPolicyCacheMode { get; set; } - /// Opaque native GitHub credential registration backing this token identity, when applicable. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("registrationId")] - public string? RegistrationId { get; set; } + /// The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// User agent to send with the policy fetch. + [JsonPropertyName("userAgent")] + public string UserAgent { get; set; } = string.Empty; } -/// Authentication-info variant backed by an SDK GitHub token callback. It carries routing metadata but never a plaintext token. -/// The token-provider variant of . +/// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoTokenProvider : AuthInfo +internal sealed class ForceLoginOrgsDecision { - /// - [JsonIgnore] - public override string Type => "token-provider"; + /// Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is never blocked. + [JsonPropertyName("allowed")] + public bool Allowed { get; set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// A stable kebab-case reason code when refused: `org-not-approved`, `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal rather than mapping it to an allow: a code this host has not been taught about still denied the credential. + [JsonPropertyName("denial")] + public string? Denial { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed because the account is approved", which a diagnostics surface needs and which also decides whether a bring-your-own-key provider may serve inference. + [JsonPropertyName("enforced")] + public bool Enforced { get; set; } - /// Opaque SDK callback registration identifier. - [JsonPropertyName("registrationId")] - public required string RegistrationId { get; set; } -} + /// The approved organization the account matched, when allowed under a pin. + [JsonPropertyName("matchedOrg")] + public string? MatchedOrg { get; set; } -/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. -/// The copilot-api-token variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoCopilotApiToken : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "copilot-api-token"; + /// A developer-facing explanation of the refusal. Omitted when allowed. + [JsonPropertyName("message")] + public string? Message { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Error-level detail from managed-policy discovery — which file failed to load, which field failed validation. Carried on the decision rather than left to the log because a refusal can exit the process before a log sink exists, which would discard the only actionable diagnostic a misconfigured managed device produces. + [JsonPropertyName("policyDiagnostics")] + public IList PolicyDiagnostics { get => field ??= []; set; } - /// Authentication host (always the public GitHub host). - [JsonPropertyName("host")] - public required string Host { get; set; } + /// The approved organization logins, as configured. Enterprise configuration rather than user data, so it is safe to name in a message or a log line. + [JsonPropertyName("requiredOrgs")] + public IList RequiredOrgs { get => field ??= []; set; } } -/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. -/// The user variant of . +/// The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoUser : AuthInfo +internal sealed class ManagedSettingsResolveStartupPolicyResult { - /// - [JsonIgnore] - public override string Type => "user"; + /// Advisory minimum client version from a successful server response. + [JsonPropertyName("clientUpdateRequested")] + public string? ClientUpdateRequested { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. + [JsonPropertyName("clientUpdateRequired")] + public string? ClientUpdateRequired { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// The device layer could not be read, so it is unconfirmed rather than known-absent. + [JsonPropertyName("deviceLoadFailed")] + public bool DeviceLoadFailed { get; set; } - /// OAuth user login. - [JsonPropertyName("login")] - public required string Login { get; set; } -} + /// The device layer discovered from the machine, when one exists. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } -/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. -/// The gh-cli variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoGhCli : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "gh-cli"; + /// The sandbox floor contributed by the device layer. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The enterprise sign-in verdict for the credential this resolution ran against, evaluated over the effective policy so a server-delivered pin is honored alongside a device one. Computed on every resolution, including one that was not retained, so a host that declines to apply policy still cannot proceed past a pin. + [JsonPropertyName("forceLoginOrgs")] + public ForceLoginOrgsDecision ForceLoginOrgs { get => field ??= new(); set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// A managed policy is known to apply to this host, from a discovered source or a resolved document. + [JsonPropertyName("managedPolicyPresent")] + public bool ManagedPolicyPresent { get; set; } - /// User login as reported by `gh auth status`. - [JsonPropertyName("login")] - public required string Login { get; set; } + /// The permissions layer specifically could not be confirmed, so permission gates apply their fail-closed posture. + [JsonPropertyName("permissionPolicyUndetermined")] + public bool PermissionPolicyUndetermined { get; set; } - /// The token returned by `gh auth token`. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } -} + /// The policy helper was configured but could not be run, or its output could not be read. + [JsonPropertyName("policyHelperLoadFailed")] + public bool PolicyHelperLoadFailed { get; set; } -/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. -/// The api-key variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoApiKey : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "api-key"; + /// The layer produced by the platform policy helper, when one ran. + [JsonPropertyName("policyHelperResponse")] + public JsonElement? PolicyHelperResponse { get; set; } - /// The API key. Treat as a secret. - [JsonPropertyName("apiKey")] - public required string ApiKey { get; set; } + /// Some layer of the policy could not be confirmed, so its absence must not be read as permission. Folds in a failed server fetch as well as an unreadable device layer. + [JsonPropertyName("policyUndetermined")] + public bool PolicyUndetermined { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The sandbox was enabled because policy could not be confirmed rather than because an administrator asked for it. Lets a host explain a sandbox the user did not configure. + [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] + public bool SandboxEnabledByUndeterminedPolicy { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } -} + /// The effective sandbox floor composed across every layer, which a host must apply rather than its own default. + [JsonPropertyName("sandboxFloor")] + public JsonElement? SandboxFloor { get; set; } -/// Current authentication state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountGetCurrentAuthResult -{ - /// Authentication errors from the last auth attempt, if any. - [JsonPropertyName("authErrors")] - public IList? AuthErrors { get; set; } + /// The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. + [JsonPropertyName("serverFetchFailed")] + public bool ServerFetchFailed { get; set; } - /// Current authentication information, if authenticated. - [JsonPropertyName("authInfo")] - public AuthInfo? AuthInfo { get; set; } + /// How the current runtime resolved the server layer. + [JsonPropertyName("serverResolution")] + public ManagedSettingsServerPolicyResolution ServerResolution { get; set; } + + /// The account's server-delivered policy, when one was resolved. + [JsonPropertyName("serverResponse")] + public JsonElement? ServerResponse { get; set; } + + /// Telemetry describing which layers answered and how, for the host to report alongside its own startup events. + [JsonPropertyName("telemetry")] + public JsonElement Telemetry { get; set; } + + /// Warnings raised while resolving, in the order they occurred. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// Authenticated account entry returned by `account.getAllUsers`. +/// Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountAllUsers +internal sealed class ManagedSettingsResolveStartupPolicyParams { - /// Authentication information for this user. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. [JsonPropertyName("authInfo")] - public AuthInfo AuthInfo { get => field ??= new(); set; } + public JsonElement? AuthInfo { get; set; } - /// Opaque identifier accepted by account and model selection APIs. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + [JsonPropertyName("bypassCacheRead")] + public bool? BypassCacheRead { get; set; } - /// Associated token, if available. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } + + /// The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } + + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + [JsonPropertyName("hasDeviceResponse")] + public bool? HasDeviceResponse { get; set; } + + /// The host's home directory, used to resolve cache and managed-file locations. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; + + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; + + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + [JsonPropertyName("policyHelperEnabled")] + public bool? PolicyHelperEnabled { get; set; } + + /// The policy-helper invocation reason. Defaults to sessionStart. + [JsonPropertyName("policyHelperReason")] + public ManagedSettingsPolicyHelperReason? PolicyHelperReason { get; set; } + + /// Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + [JsonPropertyName("policyHelperWorkingDirectory")] + public string? PolicyHelperWorkingDirectory { get; set; } + + /// Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. + [JsonPropertyName("retainAndApply")] + public bool RetainAndApply { get; set; } + + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + [JsonPropertyName("selfFetch")] + public bool? SelfFetch { get; set; } + + /// How this resolution may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two express the same decision and accepting both would leave the caller unsure which one the runtime honored. + [JsonPropertyName("serverPolicyCacheMode")] + public ManagedSettingsServerPolicyCacheMode? ServerPolicyCacheMode { get; set; } + + /// The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } + + /// User agent to send with the policy fetch. + [JsonPropertyName("userAgent")] + public string UserAgent { get; set; } = string.Empty; } -/// Result of a successful login; throws on failure. +/// The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountLoginResult +internal sealed class ManagedSettingsLoadRemoteControlResult { - /// Whether the credential was persisted to a secure store (system keychain, or the config file when plaintext storage is enabled). False when no secure store was available and the token was not saved, so the consumer can decide how to proceed. - [JsonPropertyName("storedInVault")] - public bool StoredInVault { get; set; } + /// The account's `remoteControl` policy document. Absent when no managed policy governs remote control for this account. Reported as an explicit disabled policy, rather than as absence, when the service refused to deliver a policy this client is too old to enforce. + [JsonPropertyName("remoteControl")] + public JsonElement? RemoteControl { get; set; } } -/// Credentials to validate and store. Omit login to resolve the authenticated user from the token. +/// Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountLoginRequest +internal sealed class ManagedSettingsLoadRemoteControlParams { - /// GitHub host URL. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + [JsonPropertyName("authInfo")] + public JsonElement? AuthInfo { get; set; } - /// User login/username. When omitted, the runtime validates the token and resolves the login from GitHub. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// GitHub authentication token. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; -} + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } -/// Logout result indicating if more users remain. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountLogoutResult -{ - /// Whether other authenticated users remain after logout. - [JsonPropertyName("hasMoreUsers")] - public bool HasMoreUsers { get; set; } + /// The host's environment variables, read for cache location and policy overrides. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } + + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + [JsonPropertyName("hasDeviceResponse")] + public bool? HasDeviceResponse { get; set; } + + /// The host's home directory, used to resolve cache and managed-file locations. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; + + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; + + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + [JsonPropertyName("policyHelperEnabled")] + public bool? PolicyHelperEnabled { get; set; } + + /// The policy-helper invocation reason. Defaults to sessionStart. + [JsonPropertyName("policyHelperReason")] + public ManagedSettingsPolicyHelperReason? PolicyHelperReason { get; set; } + + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + [JsonPropertyName("selfFetch")] + public bool? SelfFetch { get; set; } + + /// User agent to send with the policy fetch. + [JsonPropertyName("userAgent")] + public string UserAgent { get; set; } = string.Empty; } -/// User to log out. +/// The credential and environment to evaluate the device-channel sign-in pin against. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountLogoutRequest +internal sealed class ManagedSettingsResolveDeviceForceLoginOrgsGateParams { - /// Authentication information for the user to log out. + /// The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. [JsonPropertyName("authInfo")] - public AuthInfo? AuthInfo { get; set; } + public JsonElement? AuthInfo { get; set; } - /// Opaque account identifier returned by `account.getAllUsers`. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } } -/// Confirmation that the secret values were registered. +/// Validated device-managed settings discovered before a session exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SecretsAddFilterValuesResult +public sealed class ManagedSettingsReadResult { - /// Whether the values were successfully registered. - [JsonPropertyName("ok")] - public bool Ok { get; set; } + /// Discovery or validation error text when managed settings could not be read safely. + [JsonPropertyName("errorMessage")] + public string? ErrorMessage { get; set; } + + /// Validated, canonical managed-settings JSON. Omitted when no managed settings were discovered or when discovered settings failed validation. + [JsonPropertyName("settingsJson")] + public JsonElement? SettingsJson { get; set; } } -/// Secret values to add to the redaction filter. +/// One validation finding for a managed-settings document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SecretsAddFilterValuesRequest +public sealed class ManagedSettingsDiagnostic { - /// Raw secret values to register for redaction. - [JsonPropertyName("values")] - public IList Values { get => field ??= []; set; } + /// Human-readable description of the finding. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Dot-separated path of the offending setting, such as `autoTier.overridable`. Empty for the document as a whole. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Whether the finding rejects the document. + [JsonPropertyName("severity")] + public ManagedSettingsDiagnosticSeverity Severity { get; set; } } -/// Concrete configuration file containing an MCP server declaration. +/// One managed-settings channel and the document it delivered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSourceFile +public sealed class ManagedSettingsLayer { - /// RFC 6901 JSON Pointer to the server declaration, when known. - [JsonPropertyName("jsonPointer")] - public string? JsonPointer { get; set; } + /// Validated managed-settings document this channel delivered. Absent when the channel delivered none. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } - /// Canonical file URI for the configuration document. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// Channel identifier: `device` (MDM, plist, registry, or managed file), `server` (account or organization policy), or `policyHelper` (session-local helper output, supported by compose). Treat unknown output values as additional channels; more may be added. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; } -/// Plugin identity associated with an MCP server declaration. +/// Lock state and provenance of one managed setting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSourcePlugin +public sealed class ManagedSettingMeta { - /// Canonical plugin identity. - [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("id")] - public string Id { get; set; } = string.Empty; + /// Whether users and repositories may choose a different value. `false` means policy locks the value. + [JsonPropertyName("overridable")] + public bool Overridable { get; set; } - /// Human-readable plugin name, when available. - [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("name")] - public string? Name { get; set; } + /// Original managed value when the runtime adjusted it to a supported effective value. Omitted when no adjustment was needed. + [JsonPropertyName("requested")] + public string? Requested { get; set; } - /// Plugin version, when available. - [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("version")] - public string? Version { get; set; } + /// Channel that supplied this scalar value, matching a `layers[].source`: `device`, `server`, or `policyHelper`. These scalar defaults select one winning channel, not a mixed source. Treat unknown values as additional channels; more may be added. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; } -/// Canonical identity and location of the effective MCP server declaration. The declaration is uniquely addressed by this source id together with the discovered server name. +/// Per-key lock state and provenance for `ManagedSettingsValues`, with the same field names. Producers emit each typed key in values and meta together; both outer objects are omitted when no typed key is set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSourceRef +public sealed class ManagedSettingsMeta { - /// Open semantic editability identifier. Known values are editable and read-only. - [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("editability")] - public string Editability { get; set; } = string.Empty; - - /// Configuration file location, when the declaration is file-backed. - [JsonPropertyName("file")] - public McpSourceFile? File { get; set; } + /// Lock state and provenance of `values.autoTier`. + [JsonPropertyName("autoTier")] + public ManagedSettingMeta? AutoTier { get; set; } - /// Opaque stable identity for the configuration source. Clients must not parse this value. - [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("id")] - public string Id { get; set; } = string.Empty; + /// Lock state and provenance of `values.contextTier`. + [JsonPropertyName("contextTier")] + public ManagedSettingMeta? ContextTier { get; set; } - /// Open source-kind identifier. Known values include user, workspace, invocation, plugin, builtin, and device-registry. - [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("kind")] - public string Kind { get; set; } = string.Empty; + /// Lock state and provenance of `values.effortLevel`. + [JsonPropertyName("effortLevel")] + public ManagedSettingMeta? EffortLevel { get; set; } - /// Plugin identity, when the declaration is plugin-provided. - [JsonPropertyName("plugin")] - public McpSourcePlugin? Plugin { get; set; } + /// Lock state and provenance of `values.model`. + [JsonPropertyName("model")] + public ManagedSettingMeta? Model { get; set; } } -/// MCP server discovered by `mcp.discover`, with config source, optional plugin source, transport type, and enabled state. +/// Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredMcpServer +public sealed class ManagedSettingsResolvedData { - /// Canonical identity and location of the effective server declaration. - [JsonPropertyName("effectiveSource")] - public McpSourceRef? EffectiveSource { get; set; } + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. + [JsonPropertyName("bypassPermissionsDisabled")] + public bool BypassPermissionsDisabled { get; set; } - /// Whether the server is enabled (not in the disabled list). - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Whether a session-local permissions layer injected by the SDK host was present. + [JsonPropertyName("clientManaged")] + public bool? ClientManaged { get; set; } - /// Server name (config key). - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("name")] - public string Name { get; set; } = string.Empty; + /// Whether an actual device MDM/plist/registry/file managed-settings layer was present. + [JsonPropertyName("deviceManaged")] + public bool DeviceManaged { get; set; } - /// Configuration source: user, workspace, plugin, or builtin. - [JsonPropertyName("source")] - public McpServerSource Source { get; set; } + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. + [JsonPropertyName("failClosed")] + public bool FailClosed { get; set; } - /// Plugin name that provided this server, when source is plugin. - [JsonPropertyName("sourcePlugin")] - public string? SourcePlugin { get; set; } + /// The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. + [JsonPropertyName("managedKeys")] + public IList ManagedKeys { get => field ??= []; set; } - /// Plugin version that provided this server, when source is plugin. - [JsonPropertyName("sourcePluginVersion")] - public string? SourcePluginVersion { get; set; } + /// Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. + [JsonPropertyName("permissionsAllowIntersected")] + public bool? PermissionsAllowIntersected { get; set; } - /// Server transport type: stdio, http, sse (deprecated), or memory. - [JsonPropertyName("type")] - public DiscoveredMcpServerType? Type { get; set; } -} + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } -/// MCP servers discovered from user, workspace, plugin, and built-in sources. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDiscoverResult -{ - /// MCP servers discovered from all sources. - [JsonPropertyName("servers")] - public IList Servers { get => field ??= []; set; } -} + /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. + [JsonPropertyName("policyHelperManaged")] + public bool? PolicyHelperManaged { get; set; } -/// Optional working directory used as context for MCP server discovery. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpDiscoverRequest -{ - /// Whether to include canonical effectiveSource metadata for each discovered server. Callers must opt in so protocol-3 clients retain the legacy closed response shape. - [JsonPropertyName("includeEffectiveSource")] - public bool? IncludeEffectiveSource { get; set; } + /// Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. + [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] + public bool? SandboxEnabledByUndeterminedPolicy { get; set; } - /// Working directory used as context for discovery (e.g., plugin resolution). - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// Whether the server (account/org) managed-settings layer was present. + [JsonPropertyName("serverManaged")] + public bool ServerManaged { get; set; } + + /// The effective (resolved) managed settings values, so clients can render exactly what is enforced. Absent when no managed policy is in force. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. + [JsonPropertyName("source")] + public ManagedSettingsResolvedSource Source { get; set; } } -/// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. -/// Polymorphic base type discriminated by kind. +/// Typed effective values of managed settings. Each field mirrors the managed-settings schema key of the same name; more keys are added as they are typed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanInstallResultPlanned), "planned")] -[JsonDerivedType(typeof(McpPlanInstallResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(McpPlanInstallResultHandleRejected), "handle-rejected")] -[JsonDerivedType(typeof(McpPlanInstallResultInvalidRequest), "invalid-request")] -[JsonDerivedType(typeof(McpPlanInstallResultAuthenticationRequired), "authentication-required")] -[JsonDerivedType(typeof(McpPlanInstallResultPolicyRejected), "policy-rejected")] -[JsonDerivedType(typeof(McpPlanInstallResultNetworkFailure), "network-failure")] -[JsonDerivedType(typeof(McpPlanInstallResultUnsafeRetrieval), "unsafe-retrieval")] -[JsonDerivedType(typeof(McpPlanInstallResultMalformedCard), "malformed-card")] -[JsonDerivedType(typeof(McpPlanInstallResultContractViolation), "contract-violation")] -[JsonDerivedType(typeof(McpPlanInstallResultUnavailableTransport), "unavailable-transport")] -[JsonDerivedType(typeof(McpPlanInstallResultNotInstallable), "not-installable")] -[JsonDerivedType(typeof(McpPlanInstallResultUnavailable), "unavailable")] -public partial class McpPlanInstallResult +public sealed class ManagedSettingsValues { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Managed Auto routing preference, used when the selected model is `auto`. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } + /// Managed context-tier default for the managed concrete model. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } -/// The protocol version and capability set the runtime actually honoured for a successful catalog operation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogNegotiatedContract -{ - /// Wire features the runtime understood for this operation. Includes the five original catalog capabilities and only explicitly requested supported additions, in supported order without duplicates. Capabilities that introduce new success-union variants or operations are therefore included only when explicitly required, preserving older protocol-v3 clients. Always a superset of the caller's required features, because any shortfall is a refusal instead. Operation availability remains a separate typed result. - [JsonPropertyName("grantedCapabilities")] - public IList GrantedCapabilities { get => field ??= []; set; } + /// Managed reasoning-effort default for the managed concrete model. The runtime clamps it to an entitled effort when model availability is known. + [JsonPropertyName("effortLevel")] + public string? EffortLevel { get; set; } - /// Protocol version of the runtime that served the request. - [JsonPropertyName("runtimeProtocolVersion")] - public long RuntimeProtocolVersion { get; set; } + /// Managed default model identifier. When model availability was resolved, aliases and family names are projected to a concrete available model ID; otherwise the configured value is returned. + [JsonPropertyName("model")] + public string? Model { get; set; } } -/// The configuration-change alternative for the transportChoices entry at the same index. Only the selected alternative is applied; entries are not cumulative. The payload stays behind the runtime boundary. +/// Effective enterprise managed settings for an account, resolved without a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanConfigurationChange +public sealed class ManagedSettingsResolveResult { - /// Names of the configuration fields the change would set, without their values. - [JsonPropertyName("changedFields")] - public IList ChangedFields { get => field ??= []; set; } + /// Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. + [JsonPropertyName("account")] + public string? Account { get; set; } - /// Configuration key the change applies to. - [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("configKey")] - public string ConfigKey { get; set; } = string.Empty; + /// Warnings about unavailable policy sources or a failed refresh served from cache. A cached response is not proof of a successful live fetch; `resolved.failClosed` separately describes enforcement. + [JsonPropertyName("diagnostics")] + public IList Diagnostics { get => field ??= []; set; } - /// Whether the change would create a new entry or modify an existing one. - [JsonPropertyName("operation")] - public McpPlanConfigurationOperation Operation { get; set; } + /// Each managed-settings channel consulted, strongest first, with the validated document it delivered before merging. `resolved.settings` is the merged result. More channels may be added over time. + [JsonPropertyName("layers")] + public IList Layers { get => field ??= []; set; } - /// Scope the change would be written to. - [JsonPropertyName("scope")] - public McpPlanScope Scope { get; set; } + /// Per-key lock state and provenance for the entries in `values`, using the same key names. + [JsonPropertyName("meta")] + public ManagedSettingsMeta? Meta { get; set; } - /// Secret placeholders the written configuration would reference. The constrained placeholder type cannot carry a literal secret value. - [JsonPropertyName("secretReferences")] - public IList SecretReferences { get => field ??= []; set; } + /// Reusable source-composed permission policy for managedSettings.permissions.evaluate. Unlike resolved.settings.permissions, this retains every source's allowlist and default-prompt semantics. Refresh through resolve when account/device policy changes. Absent on runtimes that do not support permission evaluation. + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } + + /// Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. + [JsonPropertyName("resolved")] + public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } + + /// Typed effective values of managed settings, keyed like the managed-settings schema and already resolved across channels, with the `{ "overridable": ... }` wrapper removed. Present when policy sets at least one typed key. Keys not typed here are available in `resolved.settings`. + [JsonPropertyName("values")] + public ManagedSettingsValues? Values { get; set; } } -/// Normalised identity of the MCP server a plan targets, independent of how the card spelled it. +/// RPC data type for ManagedSettingsResolve operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanResourceIdentity +internal sealed class ManagedSettingsResolveRequest { - /// Canonical, normalised name of the server, for example `io.github.owner/server`. - [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("canonicalName")] - public string CanonicalName { get; set; } = string.Empty; + /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// Registry identifier of the server, when it came from a registry. - [JsonPropertyName("registryId")] - public string? RegistryId { get; set; } + /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. + [JsonPropertyName("gitHubToken")] + public string? GitHubToken { get; set; } - /// Local configuration key the server would be recorded under. - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } - /// Version advertised by the card, when it declares one. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Outcome of evaluating the planned server against registry and enterprise policy. Evaluation is read-only. +/// The authoring JSON schema for managed settings recognized by this runtime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanPolicyResult +public sealed class ManagedSettingsSchemaResult { - /// What policy decided for this server. - [JsonPropertyName("decision")] - public McpPlanPolicyDecision Decision { get; set; } + /// Version of the runtime that owns this schema. + [JsonPropertyName("runtimeVersion")] + public string RuntimeVersion { get; set; } = string.Empty; - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// JSON schema (draft 2020-12) with descriptive shared `x-composition` annotations, not a complete runtime composition contract. Model, effortLevel, and contextTier remain coupled; use `managedSettings.compose` for the runtime's effective result. + [JsonPropertyName("schema")] + public JsonElement Schema { get; set; } +} - /// Which authority produced the decision. - [JsonPropertyName("source")] - public McpPlanPolicySource Source { get; set; } +/// Result of validating a managed-settings document. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedSettingsValidateResult +{ + /// Errors that reject the document and warnings about content the runtime ignores. + [JsonPropertyName("diagnostics")] + public IList Diagnostics { get => field ??= []; set; } + + /// Canonical form of the document the runtime would apply, with unrecognized keys removed. Absent when the document is invalid. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// Whether the runtime would accept the document within the preview resource limits. Always equals whether `settings` is present. An invalid document is rejected as a whole. + [JsonPropertyName("valid")] + public bool Valid { get; set; } } -/// Semantic digest of a strictly parsed and schema-validated JSON MCP card. Both URL-backed and embedded cards are canonicalised with RFC 8785 JSON Canonicalization Scheme, encoded as UTF-8, and hashed with SHA-256. +/// A candidate managed-settings document to validate without applying it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CardDigest +internal sealed class ManagedSettingsValidateRequest { - /// Digest algorithm and canonical representation. - [JsonPropertyName("algorithm")] - public CardDigestAlgorithm Algorithm { get; set; } + /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. + [JsonPropertyName("content")] + public JsonElement Content { get; set; } - /// SHA-256 digest of the RFC 8785 canonical UTF-8 bytes, encoded as exactly 64 lowercase hexadecimal characters. - [RegularExpression("^[0-9a-f]{64}$")] - [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(64)] - [MaxLength(64)] - [JsonPropertyName("value")] - public string Value { get; set; } = string.Empty; + /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. + [JsonPropertyName("layer")] + public string? Layer { get; set; } } -/// Provenance of the exact validated JSON MCP card content bound privately to a completed plan and its opaque handle. +/// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanProvenance +public sealed class ManagedSettingsComposeResult { - /// Authority associated with the validated card, without path, query, or credentials. Inert untrusted data. - [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("authority")] - public string Authority { get; set; } = string.Empty; + /// Warnings about ignored content, with paths prefixed by the channel name. + [JsonPropertyName("diagnostics")] + public IList Diagnostics { get => field ??= []; set; } - /// Semantic digest of the exact validated JSON content bound to the plan handle. - [JsonPropertyName("cardDigest")] - public CardDigest CardDigest { get => field ??= new(); set; } + /// Only the supplied channels, strongest first, with canonical documents. Empty canonical documents are represented as absent settings, as in live resolution. + [JsonPropertyName("layers")] + public IList Layers { get => field ??= []; set; } - /// JSON MCP media type the validated card was interpreted as. - [JsonPropertyName("mediaType")] - public McpServerCardMediaType MediaType { get; set; } + /// Per-key lock state and provenance for `values`. + [JsonPropertyName("meta")] + public ManagedSettingsMeta? Meta { get; set; } - /// ISO 8601 timestamp at which the runtime completed strict parsing and schema validation of the card content. - [JsonPropertyName("validatedAt")] - public string ValidatedAt { get; set; } = string.Empty; + /// Effective managed settings, in the same shape as `session.managedSettings.get`. + [JsonPropertyName("resolved")] + public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } + + /// Typed effective values, as in `managedSettings.resolve`. + [JsonPropertyName("values")] + public ManagedSettingsValues? Values { get; set; } } -/// Where a plan would be written. +/// One candidate channel; absent settings represents a channel that delivered no document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanTarget +public sealed class ManagedSettingsComposeLayer { - /// Configuration key the server would be recorded under within that scope. - [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("configKey")] - public string ConfigKey { get; set; } = string.Empty; + /// Candidate managed-settings document. Omit when the channel delivered none, as in resolve output. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } - /// Configuration scope the plan targets. - [JsonPropertyName("scope")] - public McpPlanScope Scope { get; set; } + /// The channel whose candidate document is being supplied. + [JsonPropertyName("source")] + public ManagedSettingsChannel Source { get; set; } } -/// One eligible way to run the server, represented as a tagged package or remote variant so package identity and endpoint states cannot contradict the install method. -/// Polymorphic base type discriminated by installMethod. +/// Candidate managed-settings documents to merge without applying them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "installMethod", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanTransportChoicePackage), "package")] -[JsonDerivedType(typeof(McpPlanTransportChoiceRemote), "remote")] -public partial class McpPlanTransportChoice +internal sealed class ManagedSettingsComposeRequest { - /// The type discriminator. - [JsonPropertyName("installMethod")] - public virtual string InstallMethod { get; set; } = string.Empty; + /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. + [JsonPropertyName("layers")] + public IList Layers { get => field ??= []; set; } } - -/// One non-secret value a transport choice needs, represented as a scalar or enumerated variant so enum values cannot be missing or attached to another type. -/// Polymorphic base type discriminated by kind. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanRequiredValueScalar), "scalar")] -[JsonDerivedType(typeof(McpPlanRequiredValueEnum), "enum")] -public partial class McpPlanRequiredValue +[JsonDerivedType(typeof(ManagedPermissionOperationUrl), "url")] +public partial class ManagedPermissionOperation { /// The type discriminator. [JsonPropertyName("kind")] @@ -2276,2394 +2491,2178 @@ public partial class McpPlanRequiredValue } -/// One non-secret scalar value a transport choice needs before it can be applied. -/// The scalar variant of . +/// The url variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanRequiredValueScalar : McpPlanRequiredValue +public partial class ManagedPermissionOperationUrl : ManagedPermissionOperation { /// [JsonIgnore] - public override string Kind => "scalar"; + public override string Kind => "url"; - /// Where the value is applied when the server is launched. - [JsonPropertyName("category")] - public required McpPlanValueCategory Category { get; set; } + /// Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("defaultValue")] - public string? DefaultValue { get; set; } +/// RPC data type for ManagedPermissionEvaluation operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedPermissionEvaluation +{ + /// Original input operation associated with this verdict. + [JsonPropertyName("operation")] + public ManagedPermissionOperation Operation { get => field ??= new(); set; } - /// Human-readable explanation from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Managed-policy decision only; never bypasses user permissions or other security controls. + [JsonPropertyName("verdict")] + public ManagedPermissionVerdict Verdict { get; set; } +} - /// Whether the value may be supplied more than once. - [JsonPropertyName("isRepeated")] - public required bool IsRepeated { get; set; } +/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedSettingsPermissionsEvaluateResult +{ + /// Managed permission policy could not be determined; every operation is denied. + [JsonPropertyName("failClosed")] + public bool FailClosed { get; set; } - /// Key the value is supplied under. Inert untrusted data. - [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("key")] - public required string Key { get; set; } + /// One verdict per input operation, in the same order, including duplicates. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } +} - /// Whether the value must be present for the plan to be applicable. - [JsonPropertyName("required")] - public required bool Required { get; set; } +/// Managed policy context and ordered operations for pure, sessionless evaluation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsPermissionsEvaluateRequest +{ + /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. + [JsonPropertyName("context")] + public ManagedPermissionsContext Context { get; set; } = null!; - /// Human-readable label from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + [JsonPropertyName("operations")] + public IList Operations { get => field ??= []; set; } +} - /// Scalar type the value must conform to. - [JsonPropertyName("valueType")] - public required McpPlanScalarValueType ValueType { get; set; } +/// Hosting capabilities and session capacity advertised by an environment. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class EnvironmentCapabilities +{ + /// Advertised Agent Host Protocol version. + [JsonPropertyName("ahpVersion")] + public string? AhpVersion { get; set; } + + /// Current session count, when advertised. + [JsonPropertyName("currentSessions")] + public long? CurrentSessions { get; set; } + + /// Feature identifiers advertised by the environment. + [JsonPropertyName("features")] + public IList Features { get => field ??= []; set; } + + /// Maximum session capacity, when advertised. + [JsonPropertyName("maxSessions")] + public long? MaxSessions { get; set; } } -/// One enumerated non-secret value a transport choice needs before it can be applied. The permitted values are structurally required. -/// The enum variant of . +/// Safe discovery information. Host-side relay bootstrap credentials are never included. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanRequiredValueEnum : McpPlanRequiredValue +public sealed class GitHubEnvironment { - /// - [JsonIgnore] - public override string Kind => "enum"; + /// Hosting capabilities advertised by the environment. + [JsonPropertyName("capabilities")] + public EnvironmentCapabilities? Capabilities { get; set; } - /// Where the value is applied when the server is launched. - [JsonPropertyName("category")] - public required McpPlanValueCategory Category { get; set; } + /// Identifier assigned by Mission Control. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("defaultValue")] - public string? DefaultValue { get; set; } + /// Compute kind reported by Mission Control. + [JsonPropertyName("kind")] + public EnvironmentKind Kind { get; set; } - /// Human-readable explanation from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Discovery labels attached to the environment. + [JsonPropertyName("labels")] + public IDictionary? Labels { get; set; } - /// Non-empty permitted value set. Inert untrusted data. - [JsonPropertyName("enumValues")] - public required IList EnumValues { get; set; } + /// Timestamp of the last heartbeat received by Mission Control. + [JsonPropertyName("lastHeartbeatAt")] + public string? LastHeartbeatAt { get; set; } - /// Whether the value may be supplied more than once. - [JsonPropertyName("isRepeated")] - public required bool IsRepeated { get; set; } + /// Human-readable environment name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Key the value is supplied under. Inert untrusted data. - [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("key")] - public required string Key { get; set; } + /// Organization identifier, when the environment belongs to an organization. + [JsonPropertyName("orgId")] + public string? OrgId { get; set; } - /// Whether the value must be present for the plan to be applicable. - [JsonPropertyName("required")] - public required bool Required { get; set; } + /// Identifier of the environment owner. + [JsonPropertyName("ownerId")] + public string? OwnerId { get; set; } - /// Human-readable label from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Owner category reported by Mission Control. + [JsonPropertyName("ownerType")] + public string? OwnerType { get; set; } - /// Discriminator: the value must be one of `enumValues`. - [JsonPropertyName("valueType")] - public required McpPlanEnumValueType ValueType { get; set; } + /// Open-ended operational status vocabulary. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; } -/// A secret a transport choice needs, referenced by placeholder. No secret value ever appears in a plan, and the placeholder resolves against the keychain only when a plan is applied. +/// Environments visible to the authenticated caller and matching the supplied filters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanSecretPlaceholder +public sealed class EnvironmentsListResult { - /// Key the secret is supplied under. Inert untrusted data. - [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("key")] - public string Key { get; set; } = string.Empty; - - /// The runtime-assigned `${secret:<id>}` placeholder written into configuration in place of the value. - [JsonPropertyName("placeholder")] - public string Placeholder { get; set; } = string.Empty; - - /// Human-readable label from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Safe discovery records without relay bootstrap credentials. + [JsonPropertyName("environments")] + public IList Environments { get => field ??= []; set; } } -/// An eligible local-package transport choice. Package identity is required and a remote endpoint cannot be represented. -/// The package variant of . +/// Optional discovery filters supported by GitHub Mission Control. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanTransportChoicePackage : McpPlanTransportChoice +internal sealed class EnvironmentsListRequest { - /// - [JsonIgnore] - public override string InstallMethod => "package"; - - /// Stable identifier for this choice within the plan, used to select it when the plan is applied. - [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)] - [MaxLength(128)] - [JsonPropertyName("choiceId")] - public required string ChoiceId { get; set; } - - /// Package identifier. Inert untrusted data. - [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)] - [MaxLength(512)] - [JsonPropertyName("packageIdentifier")] - public required string PackageIdentifier { get; set; } - - /// Packaging ecosystem, for example `oci` or `npm`. - [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)] - [MaxLength(64)] - [JsonPropertyName("packageType")] - public required string PackageType { get; set; } + /// Restrict discovery to this compute kind. + [JsonPropertyName("kind")] + public EnvironmentKind? Kind { get; set; } - /// Typed values this choice requires, excluding secrets. - [JsonPropertyName("requiredValues")] - public required IList RequiredValues { get; set; } + /// Operational status, such as online, offline, degraded, waking, or draining. + [JsonPropertyName("status")] + public string? Status { get; set; } +} - /// Secrets this choice requires, referenced by placeholder only. - [JsonPropertyName("secretPlaceholders")] - public required IList SecretPlaceholders { get; set; } +/// Safe discovery information for the requested environment. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class EnvironmentsGetResult +{ + /// The requested environment without relay bootstrap credentials. + [JsonPropertyName("environment")] + public GitHubEnvironment Environment { get => field ??= new(); set; } +} - /// Local process transport this package choice would use. - [JsonPropertyName("transport")] - public required McpPlanPackageTransport Transport { get; set; } +/// Identify a Mission Control environment to retrieve. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class EnvironmentsGetRequest +{ + /// Identifier assigned by Mission Control. + [JsonPropertyName("environmentId")] + public string EnvironmentId { get; set; } = string.Empty; } -/// An eligible remote-endpoint transport choice. The endpoint is required and package identity cannot be represented. -/// The remote variant of . +/// Acknowledgement that the requested environment was deleted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanTransportChoiceRemote : McpPlanTransportChoice +public sealed class EnvironmentsDeleteResult { - /// - [JsonIgnore] - public override string InstallMethod => "remote"; +} - /// Stable identifier for this choice within the plan, used to select it when the plan is applied. - [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)] - [MaxLength(128)] - [JsonPropertyName("choiceId")] - public required string ChoiceId { get; set; } - - /// Endpoint URL. Inert untrusted data. - [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)] - [MaxLength(2048)] - [JsonPropertyName("endpoint")] - public required string Endpoint { get; set; } - - /// Typed values this choice requires, excluding secrets. - [JsonPropertyName("requiredValues")] - public required IList RequiredValues { get; set; } - - /// Secrets this choice requires, referenced by placeholder only. - [JsonPropertyName("secretPlaceholders")] - public required IList SecretPlaceholders { get; set; } - - /// Endpoint transport this remote choice would use. - [JsonPropertyName("transport")] - public required McpPlanRemoteTransport Transport { get; set; } +/// Identify a user-managed Mission Control environment to delete. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class EnvironmentsDeleteRequest +{ + /// User-managed environment to delete. GitHub-managed environments cannot be deleted. + [JsonPropertyName("environmentId")] + public string EnvironmentId { get; set; } = string.Empty; } -/// A normalised, inert description of what installing an MCP server would involve. Carries no raw card, no install specification, and no secret value. +/// The existing runtime identity and its resource on the listener. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallPlan +public sealed class HostPublishSessionResult { - /// Alternative configuration changes, with exactly one entry for each transportChoices entry in the same order. Only the entry for the subsequently selected transport applies; these are not cumulative writes. Payloads remain behind the runtime boundary. - [JsonPropertyName("configurationChanges")] - public IList ConfigurationChanges { get => field ??= []; set; } - - /// Normalised identity of the server the plan would install. - [JsonPropertyName("identity")] - public McpPlanResourceIdentity Identity { get => field ??= new(); set; } - - /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this plan. Rejected when stale, replayed, or presented to a different runtime instance. Never logged. - [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("planHandle")] - public string PlanHandle { get; set; } = string.Empty; - - /// ISO 8601 timestamp after which the plan handle is stale and will be rejected. Abandoning a plan needs no call: an unused handle simply expires, so cancellation before commit is side-effect free. - [JsonPropertyName("planHandleExpiresAt")] - public string PlanHandleExpiresAt { get; set; } = string.Empty; - - /// Outcome of evaluating the server against registry and enterprise policy. - [JsonPropertyName("policy")] - public McpPlanPolicyResult Policy { get => field ??= new(); set; } - - /// Origin and semantic digest of the exact validated JSON MCP card content bound to this plan. - [JsonPropertyName("provenance")] - public McpPlanProvenance Provenance { get => field ??= new(); set; } - - /// Identifier of the choice the runtime would pick by default. Omitted when there is no eligible transport, or when the runtime expresses no preference. - [JsonPropertyName("recommendedTransportChoiceId")] - public string? RecommendedTransportChoiceId { get; set; } - - /// Whether applying this plan would require an MCP reload to take effect. Planning itself never reloads. - [JsonPropertyName("reloadRequired")] - public bool ReloadRequired { get; set; } - - /// True only when every eligible transport choice needs additional values or secrets. False means at least one choice needs no additional configuration, not that every choice is ready. A later apply operation must validate the selected choice's own inputs, secrets and policy after explicit confirmation. - [JsonPropertyName("requiresInteractiveConfiguration")] - public bool RequiresInteractiveConfiguration { get; set; } - - /// Configuration scope and key the plan would write to. - [JsonPropertyName("target")] - public McpPlanTarget Target { get => field ??= new(); set; } + /// Canonical runtime ID of the published session. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Every eligible transport, so a host can present an explicit choice. A completed plan always has at least one; when none is eligible, planning returns `CatalogUnavailableTransportError` instead. - [JsonPropertyName("transportChoices")] - public IList TransportChoices { get => field ??= []; set; } + /// AHP resource URI for the session on this listener. + [JsonPropertyName("sessionUri")] + public string SessionUri { get; set; } = string.Empty; } -/// A computed MCP install plan. Nothing has been applied: the plan describes what installing would change, and the plan handle is what a later apply operation would consume. -/// The planned variant of . +/// Publishes a resident session attached to the listener's owning connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultPlanned : McpPlanInstallResult +internal sealed class HostPublishSessionRequest { - /// - [JsonIgnore] - public override string Kind => "planned"; - - /// Protocol version and capabilities the runtime honoured. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// Listener UUID returned by host.start. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; - /// The normalised plan. - [JsonPropertyName("plan")] - public required McpInstallPlan Plan { get; set; } + /// Canonical runtime session ID attached to the listener's owning connection. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// Metadata advertised by the AHP host, not a guarantee that history can be resumed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultNegotiationRefused : McpPlanInstallResult +public sealed class HostSessionSummary { - /// - [JsonIgnore] - public override string Kind => "negotiation-refused"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Optional activity description advertised by the host. + [JsonPropertyName("activity")] + public string? Activity { get; set; } - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("createdAt")] + public string CreatedAt { get; set; } = string.Empty; - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + /// Last modification time as an ISO 8601 timestamp. + [JsonPropertyName("modifiedAt")] + public string ModifiedAt { get; set; } = string.Empty; - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// Stable AHP resource URI identifying the session on this host. + [JsonPropertyName("resource")] + public string Resource { get; set; } = string.Empty; - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Unsigned 32-bit AHP session status bitset (0..=4294967295); unknown bits must be preserved. + [JsonPropertyName("status")] + public long Status { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// Authoritative title advertised by the host. + [JsonPropertyName("title")] + public string Title { get; set; } = string.Empty; } -/// A presented handle was not accepted. Handles are runtime-instance scoped, TTL-bound, and single-use, so each way of failing is reported distinctly. -/// The handle-rejected variant of . +/// The complete live and dormant advertised catalog, without subscribing to sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultHandleRejected : McpPlanInstallResult +public sealed class HostListSessionsResult { - /// - [JsonIgnore] - public override string Kind => "handle-rejected"; - - /// Which kind of handle was presented. - [JsonPropertyName("handleType")] - public required CatalogHandleType HandleType { get; set; } - - /// Human-readable explanation, safe to surface. Never contains the handle itself, nor a query, URL, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Why the handle was rejected. - [JsonPropertyName("reason")] - public required CatalogHandleRejectionReason Reason { get; set; } + /// Complete advertised session summaries, in the host's catalog order. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Reads a running host's catalog or the runtime's saved default catalog. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultInvalidRequest : McpPlanInstallResult +internal sealed class HostListSessionsRequest { - /// - [JsonIgnore] - public override string Kind => "invalid-request"; - - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + /// + /// Listener UUID returned by host.start; the caller must own it. Omit to read + /// the saved default compute-identity catalog without starting a listener. + /// + [JsonPropertyName("hostId")] + public string? HostId { get; set; } +} - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } +/// The resident session the application has materialized on its own connection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HostCreateSessionResult +{ + /// Runtime session UUID materialized on the application's SDK connection. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. -/// The authentication-required variant of . +/// One application-owned session handoff, requested by the supervised hosting participant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultAuthenticationRequired : McpPlanInstallResult +internal sealed class HostCreateSessionRequest { - /// - [JsonIgnore] - public override string Kind => "authentication-required"; + /// Host-selected SDK creation or resume settings, without executable callbacks or tools. + [JsonPropertyName("config")] + public IDictionary Config { get => field ??= new Dictionary(); set; } - /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Unique identity for this participation, independent of the session lifetime. + [JsonPropertyName("handoffId")] + public string HandoffId { get; set; } = string.Empty; - /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. - [JsonPropertyName("reason")] - public required CatalogAuthenticationRequiredReason Reason { get; set; } + /// + /// For an explicit publication, borrow an existing owning-connection resident + /// instead of invoking the resume factory. Cold sessions still use the factory. + /// + [JsonPropertyName("preferResident")] + public bool? PreferResident { get; set; } + + /// Resume an app-owned durable session instead of creating a new session. + [JsonPropertyName("resume")] + public bool? Resume { get; set; } } -/// Registry or enterprise policy refused the operation. -/// The policy-rejected variant of . +/// Empty acknowledgement for a completed host lifecycle operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultPolicyRejected : McpPlanInstallResult +internal sealed class HostReleaseSessionResult { - /// - [JsonIgnore] - public override string Kind => "policy-rejected"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } +} - /// Which authority produced the decision. - [JsonPropertyName("source")] - public required McpPlanPolicySource Source { get; set; } +/// Ends one participation, not the application's session lifetime. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HostReleaseSessionRequest +{ + /// Identity of the participation to release without destroying the session. + [JsonPropertyName("handoffId")] + public string HandoffId { get; set; } = string.Empty; } -/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. -/// The network-failure variant of . +/// Listener readiness, returned only after binding and the supervised participant's SDK handshake. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultNetworkFailure : McpPlanInstallResult +public sealed class HostStartResult { - /// - [JsonIgnore] - public override string Kind => "network-failure"; + /// GitHub Mission Control environment ID, present when its relay transport is ready. + [JsonPropertyName("environmentId")] + public string? EnvironmentId { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Caller-generated listener UUID. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; - /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogNetworkFailureReason Reason { get; set; } + /// Separate host process ID, when provided by a legacy runtime. Absent for in-process listeners. + [JsonPropertyName("pid")] + public long? Pid { get; set; } - /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("retryAfterSeconds")] - public int? RetryAfterSeconds { get; set; } + /// Secret connection token, absent when authentication is disabled. + [JsonPropertyName("token")] + public string? Token { get; set; } - /// HTTP status code, when the failure was a rejected response. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("statusCode")] - public int? StatusCode { get; set; } + /// Actual bound WebSocket URL, including the allocated port. + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. -/// The unsafe-retrieval variant of . +/// GitHub Mission Control registration options. The compute ID is application-owned and stable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultUnsafeRetrieval : McpPlanInstallResult +public sealed class HostGitHubEnvironmentOptions { - /// - [JsonIgnore] - public override string Kind => "unsafe-retrieval"; + /// Stable application installation identity, reused across host restarts. + [JsonPropertyName("computeId")] + public string ComputeId { get; set; } = string.Empty; - /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Human-readable environment display name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogUnsafeRetrievalReason Reason { get; set; } + /// Require sealed, connection-bound authentication (default true), independent of listener address. False permits unsealed direct credentials and unbound sealed relay credentials; use only when the caller fully controls and trusts the direct transport. Relay token encryption remains mandatory. + [JsonPropertyName("requireConnectionBinding")] + public bool? RequireConnectionBinding { get; set; } } -/// A card could not be parsed or did not satisfy its declared media type's schema. -/// The malformed-card variant of . +/// Local WebSocket transport options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultMalformedCard : McpPlanInstallResult +public sealed class HostLocalServerOptions { - /// - [JsonIgnore] - public override string Kind => "malformed-card"; + /// Listener hostname. Defaults to 127.0.0.1; explicit non-loopback binds are allowed. + [JsonPropertyName("hostname")] + public string? Hostname { get; set; } - /// Media type the card was interpreted as, when it declared one this runtime recognises. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mediaType")] - public CatalogMediaType? MediaType { get; set; } + /// Listener port. Omitted or zero requests an OS-allocated port. + [JsonPropertyName("port")] + public int? Port { get; set; } - /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Require token authentication (default true). Cannot be false with a token. + [JsonPropertyName("requireConnectionToken")] + public bool? RequireConnectionToken { get; set; } - /// How the card failed validation. - [JsonPropertyName("reason")] - public required CatalogMalformedCardReason Reason { get; set; } + /// Nonempty connection token. Generated randomly when required and omitted. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. -/// The contract-violation variant of . +/// Starts a supervised AHP host with at least one explicitly selected transport. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultContractViolation : McpPlanInstallResult +public sealed class HostStartRequest { - /// - [JsonIgnore] - public override string Kind => "contract-violation"; + /// Stable application identity selecting its durable host catalog. Defaults to the persisted runtime compute GUID; must agree with githubEnvironment.computeId when both are supplied. + [JsonPropertyName("computeId")] + public string? ComputeId { get; set; } - /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Registers a GitHub Mission Control environment and enables its relay transport. + [JsonPropertyName("githubEnvironment")] + public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } - /// Which rule the response broke. - [JsonPropertyName("reason")] - public required CatalogContractViolationReason Reason { get; set; } + /// Caller-generated UUID identifying this connection-owned listener. + [JsonPropertyName("hostId")] + public required string HostId { get; set; } + + /// Enables a local WebSocket listener. + [JsonPropertyName("localServer")] + public HostLocalServerOptions? LocalServer { get; set; } + + /// Ask the owning application to resume its durable AHP sessions. + [JsonPropertyName("resumeFactory")] + public bool? ResumeFactory { get; set; } + + /// Ask the owning SDK application to materialize AHP sessions. + [JsonPropertyName("sessionFactory")] + public bool? SessionFactory { get; set; } } -/// No transport this runtime can use is available for the requested server. -/// The unavailable-transport variant of . +/// Empty acknowledgement for a completed host lifecycle operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultUnavailableTransport : McpPlanInstallResult +public sealed class HostDisposeResult { - /// - [JsonIgnore] - public override string Kind => "unavailable-transport"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } +} - /// Why no transport could be offered. - [JsonPropertyName("reason")] - public required CatalogUnavailableTransportReason Reason { get; set; } +/// Stops a connection-owned listener and joins its teardown. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HostDisposeRequest +{ + /// Listener UUID. Unknown or successfully stopped IDs are harmless. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; } -/// The candidate is discoverable but cannot be installed. `application/ai-skill` resolves here, because it stays searchable while remaining typed non-installable. -/// The not-installable variant of . +/// Private credentials delivered only to a runtime-owned Mission Control hosting participant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultNotInstallable : McpPlanInstallResult +internal sealed class HostGetEnvironmentCredentialsResult { - /// - [JsonIgnore] - public override string Kind => "not-installable"; + /// GitHub API base URL for the authenticated service. + [JsonPropertyName("githubApiUrl")] + public string GitHubApiUrl { get; set; } = string.Empty; - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Hostname of the authenticated GitHub service. + [JsonPropertyName("githubHost")] + public string GitHubHost { get; set; } = string.Empty; - /// Why the candidate cannot be installed. - [JsonPropertyName("reason")] - public required CatalogNotInstallableReason Reason { get; set; } + /// Mission Control API origin for environment registration and management. + [JsonPropertyName("missionControlUrl")] + public string MissionControlUrl { get; set; } = string.Empty; + + /// Current bearer token for the authenticated GitHub identity. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. -/// The unavailable variant of . +/// Normalized local WebSocket listener settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultUnavailable : McpPlanInstallResult +public sealed class HostLocalServerConfiguration { - /// - [JsonIgnore] - public override string Kind => "unavailable"; + /// Hostname or IP address to bind. + [JsonPropertyName("hostname")] + public string Hostname { get; set; } = string.Empty; - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Port to bind, with zero requesting OS allocation. + [JsonPropertyName("port")] + public int Port { get; set; } - /// Why the operation is unavailable. - [JsonPropertyName("reason")] - public required CatalogUnavailableReason Reason { get; set; } + /// Whether the listener requires token authentication. + [JsonPropertyName("requireConnectionToken")] + public bool RequireConnectionToken { get; set; } + + /// Secret connection token, absent when authentication is disabled. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// The protocol version and capability set a caller requires, supplied on every catalog request so negotiation cannot be skipped by omission. +/// Normalized listener settings delivered only to the supervised hosting participant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogClientContract +internal sealed class HostGetConfigurationResult { - /// SDK protocol version the caller was generated against. A caller below the runtime's minimum supported version is refused rather than served a partial result. - [JsonPropertyName("protocolVersion")] - public long ProtocolVersion { get; set; } + /// Requested GitHub Mission Control registration. + [JsonPropertyName("githubEnvironment")] + public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } - /// Wire features the caller requires the runtime to understand. Identifiers are bounded but extensible so a newer caller can negotiate with an older runtime. Requiring an unknown feature yields a typed refusal listing what is understood, never a partial grant. A grant does not promise that a deployment has enabled the operation; typed unavailable results report that separately. - [JsonPropertyName("requiredCapabilities")] - public IList RequiredCapabilities { get => field ??= []; set; } + /// Normalized local listener settings, absent for relay-only hosts. + [JsonPropertyName("localServer")] + public HostLocalServerConfiguration? LocalServer { get; set; } + + /// Whether app-owned durable sessions are resumed by the owning application. + [JsonPropertyName("resumeFactory")] + public bool ResumeFactory { get; set; } + + /// Whether session materialization is delegated to the owning application. + [JsonPropertyName("sessionFactory")] + public bool SessionFactory { get; set; } } -/// What an install plan is computed from: a candidate handle from a previous search, or a card supplied directly. -/// Polymorphic base type discriminated by kind. +/// Empty acknowledgement for a completed host lifecycle operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanInstallSourceCandidate), "candidate")] -[JsonDerivedType(typeof(McpPlanInstallSourceCard), "card")] -public partial class McpPlanInstallSource +internal sealed class HostReadyResult { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; } - -/// Plan from a candidate returned by a previous catalog search. -/// The candidate variant of . +/// Readiness reported by the supervised hosting participant on its own SDK connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallSourceCandidate : McpPlanInstallSource +internal sealed class HostReadyRequest { - /// - [JsonIgnore] - public override string Kind => "candidate"; + /// Actual bound WebSocket URL. + [JsonPropertyName("address")] + public string? Address { get; set; } - /// Single-use candidate handle. Consumed by this call, so a replay of the same handle is rejected. - [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)] - [MaxLength(256)] - [JsonPropertyName("candidateHandle")] - public required string CandidateHandle { get; set; } + /// Registered environment ID, reported only once the relay transport is connected. + [JsonPropertyName("environmentId")] + public string? EnvironmentId { get; set; } - /// The runtime- or authority-minted `searchId` returned with the search that produced this candidate. Planning verifies the private correlation and atomically consumes a matching candidate before downstream work, including attempts that subsequently fail or report unavailable. A mismatched search does not consume the candidate. It identifies a search rather than a person and must never be joined with user identity to re-identify anyone. - [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)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Configured secret token, absent when authentication is disabled. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// A card supplied directly by the caller. Exactly one of a URL or embedded data, encoded structurally so neither both nor neither can be expressed. -/// Polymorphic base type discriminated by kind. +/// One server-discovered hook action from user, repository, plugin, or managed-policy configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpServerCardReferenceUrl), "url")] -[JsonDerivedType(typeof(McpServerCardReferenceEmbedded), "embedded")] -public partial class McpServerCardReference +public sealed class DiscoveredHook { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} - + /// Durable content hash used by hook enablement. Identical actions may intentionally share this key. Omitted when changing the user's disabled-hooks setting cannot change the action's current server-discovered state, including managed-policy hooks, session-start prompt actions, actions suppressed by disable-all settings, and projectless plugin actions that require project-directory expansion. + [JsonPropertyName("disableKey")] + public string? DisableKey { get; set; } -/// An MCP server card to be retrieved from a URL through the runtime's hardened fetch boundary. -/// The url variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpServerCardReferenceUrl : McpServerCardReference -{ - /// - [JsonIgnore] - public override string Kind => "url"; + /// Whether this action is enabled under the server-side discovery settings. Concrete sessions may differ because they can add session-specific directories, plugins, or trust. False when its disable key is present in the user's disabled-hooks setting or disable-all settings suppress the action. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Media type the card is expected to conform to. - [JsonPropertyName("mediaType")] - public required McpServerCardMediaType MediaType { get; set; } + /// Hook event that invokes this action. + [JsonPropertyName("hookType")] + public HookType HookType { get; set; } - /// Card URL. Retrieved only through the runtime's hardened boundary, with scheme, credential, address-range, redirect, timeout, and response-size controls applied. Never logged. - [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)] - [MaxLength(2048)] - [JsonPropertyName("url")] - public required string Url { get; set; } -} + /// Deterministic identifier for this server-discovered action row. It remains stable while the project, origin, source, event, action content, and duplicate ordinal are unchanged. This is row identity, not the key persisted in disabledHooks. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// An MCP server card supplied inline as an inert document. -/// The embedded variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpServerCardReferenceEmbedded : McpServerCardReference -{ - /// - [JsonIgnore] - public override string Kind => "embedded"; + /// Configuration tier that contributed this hook action. + [JsonPropertyName("origin")] + public HookOrigin Origin { get; set; } - /// The card document verbatim, treated as inert untrusted bytes. The runtime parses and validates it; the host is not expected to interpret it. Never logged. - [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)] - [MaxLength(1048576)] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Input project path for which this server-side action was resolved. Set on every row returned for project-scoped discovery, including repeated user and policy actions. + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } - /// Media type the card is expected to conform to. - [JsonPropertyName("mediaType")] - public required McpServerCardMediaType MediaType { get; set; } + /// Human-readable source label, such as a hook file path, settings source, or plugin name. + [JsonPropertyName("source")] + public string? Source { get; set; } } -/// Plan from a card supplied directly by the caller, without a preceding search. -/// The card variant of . +/// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallSourceCard : McpPlanInstallSource +public sealed class HooksDiscoverResult { - /// - [JsonIgnore] - public override string Kind => "card"; + /// Errors for hook sources or actions that could not be loaded, making the result partially incomplete. Other valid actions are still returned. Project-resolution and repository-settings errors are prefixed with their project path. + [JsonPropertyName("errors")] + public IList Errors { get => field ??= []; set; } - /// The card to plan from: exactly one of a URL or embedded data. - [JsonPropertyName("card")] - public required McpServerCardReference Card { get; set; } + /// All discovered hook actions. Byte-identical actions remain separate rows even when they share a disable key. + [JsonPropertyName("hooks")] + public IList Hooks { get => field ??= []; set; } + + /// Non-fatal source-loading warnings. Discovery remains complete for the affected source, although the source had a recoverable issue. Repository-settings warnings are prefixed with their project path when attribution is available. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. +/// Optional project paths and host-exclusion behavior for server-scoped hook discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanInstallRequest +public sealed class HooksDiscoverRequest { - /// Protocol version and capabilities the caller requires. - [JsonPropertyName("contract")] - public required CatalogClientContract Contract { get; set; } - - /// The same existing attached session that owns the original catalogue candidate. - [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)] - [MaxLength(256)] - [JsonPropertyName("policySessionId")] - public string? PolicySessionId { get; set; } + /// When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. + [JsonPropertyName("excludeHostHooks")] + public bool? ExcludeHostHooks { get; set; } - /// Configuration scope the plan targets. Defaults to user scope when omitted. - [JsonPropertyName("scope")] - public McpPlanScope? Scope { get; set; } + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("hookDirectories")] + public IList? HookDirectories { get; set; } - /// What to plan: either a candidate handle from a previous search, or a card supplied directly. - [JsonPropertyName("source")] - public required McpPlanInstallSource Source { get; set; } + /// Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } } -/// Management result with contract receipt, or a typed request/negotiation refusal. -/// Polymorphic base type discriminated by kind. +/// Active server-driven promotion for a model, including its discount and optional expiry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationManagementResultOutcome), "outcome")] -[JsonDerivedType(typeof(McpInstallationManagementResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(McpInstallationManagementResultInvalidRequest), "invalid-request")] -public partial class McpInstallationManagementResult +public sealed class ModelBillingPromo { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Percentage discount (0-100) applied while the promotion is active. May be fractional. + [JsonPropertyName("discountPercent")] + public double? DiscountPercent { get; set; } + /// UTC ISO 8601 timestamp marking when the promotion ends. Optional: an open-ended promotion omits this field. When present, the API only surfaces a promo whose expiry parses and is in the future, so consumers should treat a past value as expired. + [JsonPropertyName("endsAt")] + public string? EndsAt { get; set; } -/// Read-only or recovery management result, never permission to activate or replay. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeInstallPrepared), "install-prepared")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeListed), "listed")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecovered), "recovered")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeOperation), "operation")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeRefused), "refused")] -public partial class McpInstallationManagementOutcome -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Stable identifier for the promotion campaign. + [JsonPropertyName("id")] + public string? Id { get; set; } + /// Human-readable promotion message. Does not include the expiry timestamp; consumers may format endsAt and append it when present. + [JsonPropertyName("message")] + public string? Message { get; set; } -/// Already-confirmed durable work must be reconciled before new mutations or inventory. -/// The recovery-required variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeRecoveryRequired : McpInstallationManagementOutcome -{ - /// - [JsonIgnore] - public override string Kind => "recovery-required"; + /// Whether the service asked hosts to give this promotion a prominent surface, such as a dedicated banner, in addition to listing it with the model. `true` requests that surface and `false` asks for the model list only. Absent means the service expressed no preference — for example a response that predates the field — so hosts should apply their own default rather than read it as `false`. + [JsonPropertyName("showBanner")] + public bool? ShowBanner { get; set; } } -/// Inert, runtime-owned admission. The operation ID is known before confirmation or effects. +/// Long context tier pricing (available for models with extended context windows). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPreparedInstall +public sealed class ModelBillingTokenPricesLongContext { - /// Original plan expiry in Unix epoch milliseconds; preparation does not extend it. - [JsonPropertyName("expiresAtEpochMs")] - public long ExpiresAtEpochMs { get; set; } + /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("cachePrice")] + public double? CachePrice { get; set; } - /// Original connection-owned operation, known before the first confirmation callback. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; -} + /// AI Credits cost per billing batch of cached (read) tokens. + [JsonPropertyName("cacheReadPrice")] + public double? CacheReadPrice { get; set; } -/// The install-prepared variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeInstallPrepared : McpInstallationManagementOutcome -{ - /// - [JsonIgnore] - public override string Kind => "install-prepared"; + /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. + [JsonPropertyName("cacheWrite1hPrice")] + public double? CacheWrite1hPrice { get; set; } - /// Known original operation identity, returned before callback or effects. - [JsonPropertyName("operation")] - public required McpPreparedInstall Operation { get; set; } -} + /// AI Credits cost per billing batch of cache-write (cache creation) tokens. + [JsonPropertyName("cacheWritePrice")] + public double? CacheWritePrice { get; set; } -/// A versioned, bounded trust observation carried unchanged with a catalog candidate and its private handle context. Current observations require a recognised T1/T2 tier; every non-current state structurally forbids a tier. Eligibility remains `unknown` while Agent Finder supplies no exposure decision, and states absent from its current wire are never inferred from age, relevance, popularity, or a tier transition. -/// Polymorphic base type discriminated by status. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "status", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogTrustSnapshotCurrent), "current")] -[JsonDerivedType(typeof(CatalogTrustSnapshotAbsent), "absent")] -[JsonDerivedType(typeof(CatalogTrustSnapshotStale), "stale")] -[JsonDerivedType(typeof(CatalogTrustSnapshotDowngraded), "downgraded")] -[JsonDerivedType(typeof(CatalogTrustSnapshotRevoked), "revoked")] -[JsonDerivedType(typeof(CatalogTrustSnapshotUnsupported), "unsupported")] -[JsonDerivedType(typeof(CatalogTrustSnapshotMalformed), "malformed")] -public partial class CatalogTrustSnapshot -{ - /// The type discriminator. - [JsonPropertyName("status")] - public virtual string Status { get; set; } = string.Empty; -} + /// Use maxPromptTokens instead. Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("contextMax")] + public long? ContextMax { get; set; } + /// AI Credits cost per billing batch of input tokens. + [JsonPropertyName("inputPrice")] + public double? InputPrice { get; set; } -/// Where and when the runtime observed the trust metadata. Observation time is not the authority's evaluation time and must not be used to infer staleness. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogTrustProvenance -{ - /// ISO 8601 timestamp with a timezone offset at which the runtime observed the search result carrying this trust field. - [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(20)] - [MaxLength(64)] - [JsonPropertyName("observedAt")] - public DateTimeOffset ObservedAt { get; set; } + /// Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. + [JsonPropertyName("maxPromptTokens")] + public long? MaxPromptTokens { get; set; } - /// Bounded authority that supplied the trust field. - [JsonPropertyName("source")] - public CatalogTrustSource Source { get; set; } + /// AI Credits cost per billing batch of output tokens. + [JsonPropertyName("outputPrice")] + public double? OutputPrice { get; set; } } -/// A recognised current Agent Finder T1 or T2 trust tier. -/// The current variant of . +/// Token-level pricing information for this model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotCurrent : CatalogTrustSnapshot +public sealed class ModelBillingTokenPrices { - /// - [JsonIgnore] - public override string Status => "current"; + /// Number of tokens per standard billing batch. + [JsonPropertyName("batchSize")] + public long? BatchSize { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("cachePrice")] + public double? CachePrice { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// AI Credits cost per billing batch of cached (read) tokens. + [JsonPropertyName("cacheReadPrice")] + public double? CacheReadPrice { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. + [JsonPropertyName("cacheWrite1hPrice")] + public double? CacheWrite1hPrice { get; set; } - /// Service-computed T1 or T2 trust tier. - [JsonPropertyName("tier")] - public required CatalogTrustTier Tier { get; set; } -} + /// AI Credits cost per billing batch of cache-write (cache creation) tokens. + [JsonPropertyName("cacheWritePrice")] + public double? CacheWritePrice { get; set; } -/// Discriminator: the authority omitted trust metadata. -/// The absent variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotAbsent : CatalogTrustSnapshot -{ - /// - [JsonIgnore] - public override string Status => "absent"; + /// Use maxPromptTokens instead. Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("contextMax")] + public long? ContextMax { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// AI Credits cost per billing batch of input tokens. + [JsonPropertyName("inputPrice")] + public double? InputPrice { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Long context tier pricing (available for models with extended context windows). + [JsonPropertyName("longContext")] + public ModelBillingTokenPricesLongContext? LongContext { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. + [JsonPropertyName("maxPromptTokens")] + public long? MaxPromptTokens { get; set; } + + /// AI Credits cost per billing batch of output tokens. + [JsonPropertyName("outputPrice")] + public double? OutputPrice { get; set; } } -/// Discriminator: the authority explicitly marked the assessment stale. -/// The stale variant of . +/// Billing information. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotStale : CatalogTrustSnapshot +public sealed class ModelBilling { - /// - [JsonIgnore] - public override string Status => "stale"; + /// Whole-number percentage discount (0-100) applied to usage billed through this model. Populated for the synthetic `auto` model, where requests routed by auto-mode are billed at a reduced rate; absent for concrete models. + [JsonPropertyName("discountPercent")] + public int? DiscountPercent { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Billing cost multiplier relative to the base rate. + [JsonPropertyName("multiplier")] + public double? Multiplier { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Active server-driven promotion for this model, if any. Present when the model is being promoted with a discount, which may be time-boxed or open-ended. + [JsonPropertyName("promo")] + public ModelBillingPromo? Promo { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Token-level pricing information for this model. + [JsonPropertyName("tokenPrices")] + public ModelBillingTokenPrices? TokenPrices { get; set; } } -/// Discriminator: the authority explicitly reported a downgraded assessment. -/// The downgraded variant of . +/// Vision-specific limits. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotDowngraded : CatalogTrustSnapshot +public sealed class ModelCapabilitiesLimitsVision { - /// - [JsonIgnore] - public override string Status => "downgraded"; - - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Maximum image size in bytes. + [JsonPropertyName("max_prompt_image_size")] + public long MaxPromptImageSize { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Maximum number of images per prompt. + [JsonPropertyName("max_prompt_images")] + public long MaxPromptImages { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// MIME types the model accepts. + [JsonPropertyName("supported_media_types")] + public IList SupportedMediaTypes { get => field ??= []; set; } } -/// Discriminator: the authority explicitly revoked the assessment. -/// The revoked variant of . +/// Token limits for prompts, outputs, and context window. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotRevoked : CatalogTrustSnapshot +public sealed class ModelCapabilitiesLimits { - /// - [JsonIgnore] - public override string Status => "revoked"; + /// Maximum total context window size in tokens. + [JsonPropertyName("max_context_window_tokens")] + public long? MaxContextWindowTokens { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Maximum number of output/completion tokens. + [JsonPropertyName("max_output_tokens")] + public long? MaxOutputTokens { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Maximum number of prompt/input tokens. + [JsonPropertyName("max_prompt_tokens")] + public long? MaxPromptTokens { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Vision-specific limits. + [JsonPropertyName("vision")] + public ModelCapabilitiesLimitsVision? Vision { get; set; } } -/// Discriminator: the authority supplied a bounded trust value this runtime does not understand. -/// The unsupported variant of . +/// Feature flags indicating what the model supports. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotUnsupported : CatalogTrustSnapshot +public sealed class ModelCapabilitiesSupports { - /// - [JsonIgnore] - public override string Status => "unsupported"; + /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). + [JsonPropertyName("adaptive_thinking")] + public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Whether this model supports reasoning effort configuration. + [JsonPropertyName("reasoningEffort")] + public bool? ReasoningEffort { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Whether the model supports provider-native thinking. Independent of configurable reasoning effort; omission means unknown. + [JsonPropertyName("thinking")] + public bool? Thinking { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Whether this model supports canonical tool calling. + [JsonPropertyName("toolCalls")] + public bool? ToolCalls { get; set; } + + /// Whether this model supports vision/image input. + [JsonPropertyName("vision")] + public bool? Vision { get; set; } } -/// Discriminator: the trust field was empty, unbounded, or had the wrong JSON type. -/// The malformed variant of . +/// Model capabilities and limits. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotMalformed : CatalogTrustSnapshot +public sealed class ModelCapabilities { - /// - [JsonIgnore] - public override string Status => "malformed"; + /// Token limits for prompts, outputs, and context window. + [JsonPropertyName("limits")] + public ModelCapabilitiesLimits? Limits { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Feature flags indicating what the model supports. + [JsonPropertyName("supports")] + public ModelCapabilitiesSupports? Supports { get; set; } +} - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } +/// A service-published message about a model, carrying a stable machine-readable code alongside human-readable text. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModelMessage +{ + /// Stable machine-readable identifier for the message, such as `client_version_deprecated`. Hosts can key custom presentation off this; unrecognized codes should fall back to displaying `message`. + [JsonPropertyName("code")] + public string Code { get; set; } = string.Empty; - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Human-readable message text intended for display to the user. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// Catalogue identity retained from a bound candidate or plan at installation time. +/// Policy state (if applicable). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstallationCatalogueIdentity +public sealed class ModelPolicy { - /// Catalogue description retained at install planning time. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Current policy state for this model. + [JsonPropertyName("state")] + public ModelPolicyState State { get; set; } - /// Human display name retained from the catalogue candidate. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// Usage terms or conditions for this model. + [JsonPropertyName("terms")] + public string? Terms { get; set; } +} - /// Catalogue item URL when supplied by the authority. - [JsonPropertyName("itemUrl")] - public string? ItemUrl { get; set; } +/// Service-published warning text that hosts should display when presenting a model. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModelWarningText +{ + /// Data-retention warning for the model. The text may contain Markdown links and should be rendered as Markdown when supported. + [JsonPropertyName("dataRetention")] + public string? DataRetention { get; set; } +} - /// Catalogue publisher retained at install planning time. - [JsonPropertyName("publisher")] - public string? Publisher { get; set; } +/// Copilot model metadata, including identifier, display name, capabilities, policy, billing, reasoning efforts, and picker categories. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class Model +{ + /// Billing information. + [JsonPropertyName("billing")] + public ModelBilling? Billing { get; set; } - /// Authority resource identifier when supplied by the catalogue. - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Model capabilities and limits. + [JsonPropertyName("capabilities")] + public ModelCapabilities Capabilities { get => field ??= new(); set; } - /// Catalogue authority/source string that supplied the candidate. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Default reasoning effort level (only present if model supports reasoning effort). + [JsonPropertyName("defaultReasoningEffort")] + public string? DefaultReasoningEffort { get; set; } - /// Catalogue trust observation retained at install planning time. - [JsonPropertyName("trustAtInstall")] - public CatalogTrustSnapshot? TrustAtInstall { get; set; } + /// Model identifier (e.g., "claude-sonnet-4.5"). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Catalogue version retained at install planning time. - [JsonPropertyName("version")] - public string? Version { get; set; } -} + /// Informational notices the service published for this model, such as an upcoming change or a recommended alternative. Present only when the service published at least one notice. Hosts should surface these without implying anything is wrong with the model. + [JsonPropertyName("infoMessages")] + public IList? InfoMessages { get; set; } -/// Durable configuration ownership is distinct from session-specific usability. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationSummary -{ - /// Catalogue identity retained from the installed plan when available. - [JsonPropertyName("catalogue")] - public InstallationCatalogueIdentity? Catalogue { get; set; } + /// Provider-supplied model metadata. Keys and JSON-compatible values are preserved unchanged. This is factual metadata published by the model provider; it carries no picker or UX semantics. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } - /// Exact alternative retained in the installing receipt. - [JsonPropertyName("choiceId")] - public string ChoiceId { get; set; } = string.Empty; + /// Model capability category for grouping in the model picker. + [JsonPropertyName("modelPickerCategory")] + public ModelPickerCategory? ModelPickerCategory { get; set; } - /// Identity retained from the validated original plan. - [JsonPropertyName("identity")] - public McpPlanResourceIdentity Identity { get => field ??= new(); set; } + /// Relative cost tier for token-based billing users. + [JsonPropertyName("modelPickerPriceCategory")] + public ModelPickerPriceCategory? ModelPickerPriceCategory { get; set; } - /// Exact durable installation receipt identity. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// Display name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// ISO 8601 wall-clock installation time when available. - [JsonPropertyName("installedAt")] - public string? InstalledAt { get; set; } + /// Policy state (if applicable). + [JsonPropertyName("policy")] + public ModelPolicy? Policy { get; set; } - /// Original installing operation, not a fresh management operation. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// The model provider that produced this model, as a neutral reference (opaque id, human-readable label, and provider kind). Present on models returned by `session.model.list`, which resolves provider attribution from the session's account roster; absent on the flat `server.models.list`, which does not resolve a session roster. The model picker groups by this reference. + [JsonPropertyName("provider")] + public ModelProviderRef? Provider { get; set; } - /// Ownership or setup state, never inferred proof of tool usability. - [JsonPropertyName("state")] - public McpInstallationState State { get; set; } + /// Context-window tiers this model offers, when the provider advertises them independently of tiered token pricing. Copilot models carry their tiers in `billing.tokenPrices`; a provider that has no pricing to publish (an agent host reached over AHP, for example) declares them here instead, so the model picker can still offer the tier toggle. + [JsonPropertyName("supportedContextTiers")] + public IList? SupportedContextTiers { get; set; } + + /// Supported reasoning effort levels (only present if model supports reasoning effort). + [JsonPropertyName("supportedReasoningEfforts")] + public IList? SupportedReasoningEfforts { get; set; } + + /// Model vendor as the Copilot API reports it, for example "Anthropic" or "Azure OpenAI". Open vocabulary, passed through unchanged. It can name the vendor that serves the model instead of the one that built it, or a label that is not a vendor, such as "Experimental". Absent when the Copilot API reports no vendor. + [JsonPropertyName("vendor")] + public string? Vendor { get; set; } + + /// Warnings the service published for this model, such as a deprecated client version. Present only when the service published at least one warning. The model remains usable; hosts should surface these as advisory rather than blocking. + [JsonPropertyName("warningMessages")] + public IList? WarningMessages { get; set; } + + /// Warning text the service requires hosts to surface for this model. Present only when the service published at least one warning. + [JsonPropertyName("warningText")] + public ModelWarningText? WarningText { get; set; } } -/// The listed variant of . +/// List of Copilot models available to the resolved user, including capabilities and billing metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeListed : McpInstallationManagementOutcome +public sealed class ModelList { - /// - [JsonIgnore] - public override string Kind => "listed"; - - /// Owned receipts visible to the selected account and host. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } + /// List of available models with full metadata. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } } -/// The recovered variant of . +/// RPC data type for ModelsList operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeRecovered : McpInstallationManagementOutcome +internal sealed class ModelsListRequest { - /// - [JsonIgnore] - public override string Kind => "recovered"; + /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. + [JsonPropertyName("gitHubToken")] + public string? GitHubToken { get; set; } - /// Freshly inspected receipts after successful durable reconciliation. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } } -/// Exact inert removal plan. No configuration or credentials have changed. +/// A well-known model in the runtime's built-in catalog. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpUninstallPlan +public sealed class BuiltInModelCatalogEntry { - /// Original wall-clock expiry in milliseconds. Applying never renews it. - [JsonPropertyName("expiresAtEpochMs")] - public long ExpiresAtEpochMs { get; set; } + /// Well-known runtime model ID suitable for provider or provider-model metadata. This is not necessarily the provider-facing deployment or model name and does not indicate CAPI entitlement or provider availability. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; +} - /// Original owned receipt being removed. - [JsonPropertyName("installation")] - public McpInstallationSummary Installation { get => field ??= new(); set; } +/// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class BuiltInModelCatalog +{ + /// Built-in model entries. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } +} - /// The original operation, inspectable and cancellable on this same connection. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; +/// Built-in tool metadata with identifier, optional namespaced name, description, input-parameter schema, and usage instructions. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class Tool +{ + /// Description of what the tool does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Exact configured input slots owned by this installation, never shared OAuth tokens. - [JsonPropertyName("ownedSecretCount")] - public long OwnedSecretCount { get; set; } + /// Optional instructions for how to use this tool effectively. + [JsonPropertyName("instructions")] + public string? Instructions { get; set; } - /// One-use original connection and authority-bound plan handle. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Tool identifier (e.g., "bash", "grep", "str_replace_editor"). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Shared authentication is deliberately retained; revocation is a separate action. - [JsonPropertyName("preservesSharedAuthentication")] - public bool PreservesSharedAuthentication { get; set; } + /// Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools). + [JsonPropertyName("namespacedName")] + public string? NamespacedName { get; set; } - /// Whether removal restores a protected earlier configuration. - [JsonPropertyName("restoresPreviousConfiguration")] - public bool RestoresPreviousConfiguration { get; set; } + /// JSON Schema for the tool's input parameters. + [JsonPropertyName("parameters")] + public IDictionary? Parameters { get; set; } + + /// Telemetry-safety policy for the tool name and input names, not input values. Treat omitted metadata as unsafe. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("safeForTelemetry")] + public JsonElement? SafeForTelemetry { get; set; } } -/// The uninstall-planned variant of . +/// Built-in tools available for the requested model, with their parameters and instructions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeUninstallPlanned : McpInstallationManagementOutcome +public sealed class ToolList { - /// - [JsonIgnore] - public override string Kind => "uninstall-planned"; - - /// Original owned removal plan and operation. - [JsonPropertyName("plan")] - public required McpUninstallPlan Plan { get; set; } + /// List of available built-in tools with metadata. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } } -/// Status snapshot from the original connection, independent of new-work account availability. -/// Polymorphic base type discriminated by phase. +/// Optional model identifier whose tool overrides should be applied to the listing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "phase", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationOperationStatusPreparing), "preparing")] -[JsonDerivedType(typeof(McpInstallationOperationStatusPrepared), "prepared")] -[JsonDerivedType(typeof(McpInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] -[JsonDerivedType(typeof(McpInstallationOperationStatusRevalidating), "revalidating")] -[JsonDerivedType(typeof(McpInstallationOperationStatusApplying), "applying")] -[JsonDerivedType(typeof(McpInstallationOperationStatusCompleted), "completed")] -public partial class McpInstallationOperationStatus +internal sealed class ToolsListRequest { - /// The type discriminator. - [JsonPropertyName("phase")] - public virtual string Phase { get; set; } = string.Empty; + /// Optional model ID — when provided, the returned tool list reflects model-specific overrides. + [JsonPropertyName("model")] + public string? Model { get; set; } } - -/// The preparing variant of . +/// Quota usage snapshot for a Copilot quota type, including entitlement, used requests, overage, reset date, and remaining percentage. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusPreparing : McpInstallationOperationStatus +public sealed class AccountQuotaSnapshot { - /// - [JsonIgnore] - public override string Phase => "preparing"; - - /// Whether cancellation has been requested, not proof that a write was undone. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Number of requests included in the entitlement, or -1 for unlimited entitlements. + [JsonPropertyName("entitlementRequests")] + public long EntitlementRequests { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Whether the user has an unlimited usage entitlement. + [JsonPropertyName("isUnlimitedEntitlement")] + public bool IsUnlimitedEntitlement { get; set; } -/// The prepared variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusPrepared : McpInstallationOperationStatus -{ - /// - [JsonIgnore] - public override string Phase => "prepared"; + /// Number of additional usage requests made this period. + [JsonPropertyName("overage")] + public double Overage { get; set; } - /// Whether the inert prepared operation was asked to cancel. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Whether additional usage is allowed when quota is exhausted. + [JsonPropertyName("overageAllowedWithExhaustedQuota")] + public bool OverageAllowedWithExhaustedQuota { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Percentage of entitlement remaining. + [JsonPropertyName("remainingPercentage")] + public double RemainingPercentage { get; set; } -/// The awaiting-confirmation variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusAwaitingConfirmation : McpInstallationOperationStatus -{ - /// - [JsonIgnore] - public override string Phase => "awaiting-confirmation"; + /// Date when the quota resets (ISO 8601 string). + [JsonPropertyName("resetDate")] + public DateTimeOffset? ResetDate { get; set; } - /// Whether the pending human callback was asked to cancel. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Whether usage is still permitted after quota exhaustion. + [JsonPropertyName("usageAllowedWithExhaustedQuota")] + public bool UsageAllowedWithExhaustedQuota { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Number of requests used so far this period. + [JsonPropertyName("usedRequests")] + public long UsedRequests { get; set; } } -/// The revalidating variant of . +/// Quota usage snapshots for the resolved user, keyed by quota type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusRevalidating : McpInstallationOperationStatus +public sealed class AccountGetQuotaResult { - /// - [JsonIgnore] - public override string Phase => "revalidating"; - - /// Whether source or authority revalidation was asked to cancel. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } - - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Quota snapshots keyed by type (e.g., chat, completions, premium_interactions). + [JsonPropertyName("quotaSnapshots")] + public IDictionary QuotaSnapshots { get => field ??= new Dictionary(); set; } } -/// The applying variant of . +/// RPC data type for AccountGetQuota operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusApplying : McpInstallationOperationStatus +internal sealed class AccountGetQuotaRequest { - /// - [JsonIgnore] - public override string Phase => "applying"; - - /// Whether applying was asked to cancel; already-started effects retain their lease. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. + [JsonPropertyName("gitHubToken")] + public string? GitHubToken { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } } -/// Terminal mutation result. Uncertainty is not approval, rollback or permission to replay. -/// Polymorphic base type discriminated by kind. +/// Authentication credentials accepted only at native protocol ingress. Runtime outputs use credential-free `AuthIdentity` metadata. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", + TypeDiscriminatorPropertyName = "type", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationOutcomeInstalled), "installed")] -[JsonDerivedType(typeof(McpInstallationOutcomeUninstalled), "uninstalled")] -[JsonDerivedType(typeof(McpInstallationOutcomeRolledBack), "rolled-back")] -[JsonDerivedType(typeof(McpInstallationOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(McpInstallationOutcomeDeclined), "declined")] -[JsonDerivedType(typeof(McpInstallationOutcomeCancelled), "cancelled")] -[JsonDerivedType(typeof(McpInstallationOutcomeRefused), "refused")] -public partial class McpInstallationOutcome +[JsonDerivedType(typeof(AuthInfoHmac), "hmac")] +[JsonDerivedType(typeof(AuthInfoEnv), "env")] +[JsonDerivedType(typeof(AuthInfoToken), "token")] +[JsonDerivedType(typeof(AuthInfoTokenProvider), "token-provider")] +[JsonDerivedType(typeof(AuthInfoCopilotApiToken), "copilot-api-token")] +[JsonDerivedType(typeof(AuthInfoUser), "user")] +[JsonDerivedType(typeof(AuthInfoAccount), "account")] +[JsonDerivedType(typeof(AuthInfoGhCli), "gh-cli")] +[JsonDerivedType(typeof(AuthInfoApiKey), "api-key")] +public partial class AuthInfo { /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// The installed variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeInstalled : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "installed"; - - /// Durable installation succeeded but final transaction cleanup remains. - [JsonPropertyName("cleanupPending")] - public required bool CleanupPending { get; set; } - - /// Receipt identity produced by the confirmed transaction. - [JsonPropertyName("installation")] - public required McpInstallationSummary Installation { get; set; } -} - -/// The uninstalled variant of . +/// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeUninstalled : McpInstallationOutcome +public sealed class CopilotUserResponseEndpoints { - /// - [JsonIgnore] - public override string Kind => "uninstalled"; - - /// Durable removal succeeded but final cleanup remains. - [JsonPropertyName("cleanupPending")] - public required bool CleanupPending { get; set; } + /// Copilot API endpoint URL. + [JsonPropertyName("api")] + public string? Api { get; set; } - /// Exact removed receipt identity. - [JsonPropertyName("installationId")] - public required string InstallationId { get; set; } + /// Experimental-service endpoint URL. + [JsonPropertyName("exp")] + public string? Exp { get; set; } - /// Original removal operation. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Origin-tracker endpoint URL. + [JsonPropertyName("origin-tracker")] + public string? OriginTracker { get; set; } - /// Any grants in the incumbent shared OAuth store remain unowned and retained. - [JsonPropertyName("preservedSharedAuthentication")] - public required bool PreservedSharedAuthentication { get; set; } + /// Copilot proxy endpoint URL. + [JsonPropertyName("proxy")] + public string? Proxy { get; set; } - /// Exact owned input slots removed, excluding shared OAuth credentials. - [JsonPropertyName("removedOwnedSecrets")] - public required long RemovedOwnedSecrets { get; set; } + /// Copilot telemetry endpoint URL. + [JsonPropertyName("telemetry")] + public string? Telemetry { get; set; } +} - /// Whether protected pre-install configuration was restored. - [JsonPropertyName("restoredPreviousConfiguration")] - public required bool RestoredPreviousConfiguration { get; set; } +/// RPC data type for CopilotUserResponseEnterpriseListItem operations. +public sealed class CopilotUserResponseEnterpriseListItem +{ + /// JavaScript-safe numeric database ID of the enterprise. + [JsonPropertyName("id")] + public long? Id { get; set; } } -/// The durable transaction was aborted or fully compensated. -/// The rolled-back variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeRolledBack : McpInstallationOutcome +/// RPC data type for CopilotUserResponseOrganizationListItem operations. +public sealed class CopilotUserResponseOrganizationListItem { - /// - [JsonIgnore] - public override string Kind => "rolled-back"; + /// Numeric database ID of the organization. + [JsonPropertyName("id")] + public double? Id { get; set; } - /// Original connection-owned operation. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// GitHub login of the organization. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Cause of the fully aborted or compensated operation. - [JsonPropertyName("reason")] - public required McpInstallationFailureReason Reason { get; set; } + /// Display name of the organization. + [JsonPropertyName("name")] + public string? Name { get; set; } } -/// A write may have completed. Recover and inspect durable state before retrying. -/// The recovery-required variant of . +/// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeRecoveryRequired : McpInstallationOutcome +public sealed class CopilotUserResponseQuotaSnapshotsChat { - /// - [JsonIgnore] - public override string Kind => "recovery-required"; + /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. + [JsonPropertyName("entitlement")] + public double? Entitlement { get; set; } - /// Operation whose durable result must be recovered and inspected. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. + [JsonPropertyName("has_quota")] + public bool? HasQuota { get; set; } -/// The declined variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeDeclined : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "declined"; + /// Count of additional pay-per-request usage consumed this period beyond the entitlement. + [JsonPropertyName("overage_count")] + public double? OverageCount { get; set; } - /// Original operation explicitly declined by the user. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. + [JsonPropertyName("overage_permitted")] + public bool? OveragePermitted { get; set; } -/// The cancelled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeCancelled : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// Percentage of the entitlement remaining at the snapshot timestamp. + [JsonPropertyName("percent_remaining")] + public double? PercentRemaining { get; set; } - /// Original operation cancelled before a terminal application result. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Identifier of the quota bucket this snapshot describes. + [JsonPropertyName("quota_id")] + public string? QuotaId { get; set; } -/// The refused variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeRefused : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "refused"; + /// Amount of quota remaining at the snapshot timestamp. + [JsonPropertyName("quota_remaining")] + public double? QuotaRemaining { get; set; } - /// Present once an operation has been allocated; never a plan handle. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operationId")] - public string? OperationId { get; set; } + /// Unix epoch time, in seconds, when this quota next resets. + [JsonPropertyName("quota_reset_at")] + public double? QuotaResetAt { get; set; } - /// Specific bounded refusal, never a success-shaped fallback. - [JsonPropertyName("reason")] - public required McpInstallationFailureReason Reason { get; set; } + /// Remaining entitlement/quota amount at the snapshot timestamp. + [JsonPropertyName("remaining")] + public double? Remaining { get; set; } + + /// UTC timestamp when this snapshot was captured. + [JsonPropertyName("timestamp_utc")] + public string? TimestampUtc { get; set; } + + /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } + + /// Whether the entitlement for this category is unlimited. + [JsonPropertyName("unlimited")] + public bool? Unlimited { get; set; } } -/// The completed variant of . +/// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusCompleted : McpInstallationOperationStatus +public sealed class CopilotUserResponseQuotaSnapshotsCompletions { - /// - [JsonIgnore] - public override string Phase => "completed"; + /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. + [JsonPropertyName("entitlement")] + public double? Entitlement { get; set; } - /// Whether cancellation was requested before the terminal result. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. + [JsonPropertyName("has_quota")] + public bool? HasQuota { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Count of additional pay-per-request usage consumed this period beyond the entitlement. + [JsonPropertyName("overage_count")] + public double? OverageCount { get; set; } - /// Immutable terminal receipt. - [JsonPropertyName("outcome")] - public required McpInstallationOutcome Outcome { get; set; } -} + /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. + [JsonPropertyName("overage_permitted")] + public bool? OveragePermitted { get; set; } -/// The operation variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeOperation : McpInstallationManagementOutcome -{ - /// - [JsonIgnore] - public override string Kind => "operation"; + /// Percentage of the entitlement remaining at the snapshot timestamp. + [JsonPropertyName("percent_remaining")] + public double? PercentRemaining { get; set; } - /// Original-connection operation snapshot. - [JsonPropertyName("operation")] - public required McpInstallationOperationStatus Operation { get; set; } -} + /// Identifier of the quota bucket this snapshot describes. + [JsonPropertyName("quota_id")] + public string? QuotaId { get; set; } -/// The refused variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeRefused : McpInstallationManagementOutcome -{ - /// - [JsonIgnore] - public override string Kind => "refused"; + /// Amount of quota remaining at the snapshot timestamp. + [JsonPropertyName("quota_remaining")] + public double? QuotaRemaining { get; set; } - /// Specific bounded refusal. - [JsonPropertyName("reason")] - public required McpInstallationFailureReason Reason { get; set; } -} + /// Unix epoch time, in seconds, when this quota next resets. + [JsonPropertyName("quota_reset_at")] + public double? QuotaResetAt { get; set; } -/// The outcome variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementResultOutcome : McpInstallationManagementResult -{ - /// - [JsonIgnore] - public override string Kind => "outcome"; + /// Remaining entitlement/quota amount at the snapshot timestamp. + [JsonPropertyName("remaining")] + public double? Remaining { get; set; } - /// Capabilities actually honoured for this request. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// UTC timestamp when this snapshot was captured. + [JsonPropertyName("timestamp_utc")] + public string? TimestampUtc { get; set; } - /// Observed management outcome. - [JsonPropertyName("outcome")] - public required McpInstallationManagementOutcome Outcome { get; set; } + /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } + + /// Whether the entitlement for this category is unlimited. + [JsonPropertyName("unlimited")] + public bool? Unlimited { get; set; } } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementResultNegotiationRefused : McpInstallationManagementResult +public sealed class CopilotUserResponseQuotaSnapshotsPremiumInteractions { - /// - [JsonIgnore] - public override string Kind => "negotiation-refused"; + /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. + [JsonPropertyName("entitlement")] + public double? Entitlement { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. + [JsonPropertyName("has_quota")] + public bool? HasQuota { get; set; } - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } + /// Count of additional pay-per-request usage consumed this period beyond the entitlement. + [JsonPropertyName("overage_count")] + public double? OverageCount { get; set; } - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. + [JsonPropertyName("overage_permitted")] + public bool? OveragePermitted { get; set; } - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// Percentage of the entitlement remaining at the snapshot timestamp. + [JsonPropertyName("percent_remaining")] + public double? PercentRemaining { get; set; } - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Identifier of the quota bucket this snapshot describes. + [JsonPropertyName("quota_id")] + public string? QuotaId { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } -} + /// Amount of quota remaining at the snapshot timestamp. + [JsonPropertyName("quota_remaining")] + public double? QuotaRemaining { get; set; } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementResultInvalidRequest : McpInstallationManagementResult -{ - /// - [JsonIgnore] - public override string Kind => "invalid-request"; + /// Unix epoch time, in seconds, when this quota next resets. + [JsonPropertyName("quota_reset_at")] + public double? QuotaResetAt { get; set; } - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + /// Remaining entitlement/quota amount at the snapshot timestamp. + [JsonPropertyName("remaining")] + public double? Remaining { get; set; } - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// UTC timestamp when this snapshot was captured. + [JsonPropertyName("timestamp_utc")] + public string? TimestampUtc { get; set; } + + /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } + + /// Whether the entitlement for this category is unlimited. + [JsonPropertyName("unlimited")] + public bool? Unlimited { get; set; } } -/// One Registry string-valued configuration entry for the selected transport. +/// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationInput +public sealed class CopilotUserResponseQuotaSnapshots { - /// Exact category declared by the selected choice. - [JsonPropertyName("category")] - public McpPlanValueCategory Category { get; set; } + /// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. + [JsonPropertyName("chat")] + public CopilotUserResponseQuotaSnapshotsChat? Chat { get; set; } - /// Exact key declared by the selected choice. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. + [JsonPropertyName("completions")] + public CopilotUserResponseQuotaSnapshotsCompletions? Completions { get; set; } - /// Explicit non-secret value. Secret placeholders use a separate input channel. - [JsonPropertyName("value")] - public string Value { get; set; } = string.Empty; + /// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. + [JsonPropertyName("premium_interactions")] + public CopilotUserResponseQuotaSnapshotsPremiumInteractions? PremiumInteractions { get; set; } } -/// A request-local value for one exact reviewed placeholder. Never logged or persisted in a plan. +/// 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationSecret +public sealed class CopilotUserResponse { - /// Exact placeholder from the selected choice, not a caller-chosen backend identifier. - [JsonPropertyName("placeholder")] - public string Placeholder { get; set; } = string.Empty; + /// Copilot access SKU identifier (e.g. `free_limited_copilot`, `copilot_for_business_seat_quota`) used to gate model and feature access. + [JsonPropertyName("access_type_sku")] + public string? AccessTypeSku { get; set; } - /// Fresh explicit secret value. It is omitted from confirmation reviews and telemetry. - [JsonPropertyName("value")] - public string Value { get; set; } = string.Empty; -} + /// Opaque analytics tracking identifier for the user, forwarded from the Copilot API. + [JsonPropertyName("analytics_tracking_id")] + public string? AnalyticsTrackingId { get; set; } -/// Side-effect-free preparation of one original bound remote MCP choice. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPrepareInstallRequest -{ - /// Exact selected alternative from that plan. - [JsonPropertyName("choiceId")] - public string ChoiceId { get; set; } = string.Empty; + /// Date the Copilot seat was assigned to the user, if applicable. + [JsonPropertyName("assigned_date")] + public string? AssignedDate { get; set; } - /// Required bound catalogue and confirmed remote installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Whether the user is eligible to sign up for the free/limited Copilot tier. + [JsonPropertyName("can_signup_for_limited")] + public bool? CanSignupForLimited { get; set; } - /// - /// Declared non-secret values. Non-empty only when the caller requires - /// `mcp-configured-remote-installation`; omitted values use the card default. - /// - [JsonPropertyName("inputs")] - public IList Inputs { get => field ??= []; set; } + /// Whether the user is able to upgrade their Copilot plan. + [JsonPropertyName("can_upgrade_plan")] + public bool? CanUpgradePlan { get; set; } - /// Original single-use bound plan, never a client-authored configuration. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Whether Copilot chat is enabled for the user. + [JsonPropertyName("chat_enabled")] + public bool? ChatEnabled { get; set; } - /// An existing local session attached to this connection, not permission to attach one. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Whether CLI remote control is enabled for the user. + [JsonPropertyName("cli_remote_control_enabled")] + public bool? CliRemoteControlEnabled { get; set; } - /// - /// One entry per declared secret placeholder of the selected choice. Non-empty - /// only when the caller requires `mcp-configured-remote-installation`. - /// - [JsonPropertyName("secrets")] - public IList Secrets { get => field ??= []; set; } + /// Whether cloud session storage is enabled for the user. + [JsonPropertyName("cloud_session_storage_enabled")] + public bool? CloudSessionStorageEnabled { get; set; } - /// The trusted host presents this choice alongside the exact secret placeholders. - [JsonPropertyName("secretStorage")] - public McpInstallationSecretStorage SecretStorage { get; set; } + /// Whether the Codex agent is enabled for the user. + [JsonPropertyName("codex_agent_enabled")] + public bool? CodexAgentEnabled { get; set; } - /// The exact original source, used transiently only after confirmation. - [JsonPropertyName("source")] - public McpServerCardReference Source { get => field ??= new(); set; } -} + /// Copilot plan name for the user (e.g. `individual`, `business`, `enterprise`). + [JsonPropertyName("copilot_plan")] + public string? CopilotPlan { get; set; } -/// An installation result together with the exact honoured contract, or a negotiation refusal. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationResultOutcome), "outcome")] -[JsonDerivedType(typeof(McpInstallationResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(McpInstallationResultInvalidRequest), "invalid-request")] -public partial class McpInstallationResult -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Whether `.copilotignore` content-exclusion support is enabled for the user. + [JsonPropertyName("copilotignore_enabled")] + public bool? CopilotignoreEnabled { get; set; } + /// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. + [JsonPropertyName("endpoints")] + public CopilotUserResponseEndpoints? Endpoints { get; set; } -/// The outcome variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationResultOutcome : McpInstallationResult -{ - /// - [JsonIgnore] - public override string Kind => "outcome"; + /// Enterprises that provide the user's Copilot license; malformed entries are normalized to null or ID-less shapes. + [JsonPropertyName("enterprise_list")] + public IList? EnterpriseList { get; set; } - /// Capabilities actually honoured for this request. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// Whether MCP (Model Context Protocol) support is enabled for the user. + [JsonPropertyName("is_mcp_enabled")] + public bool? IsMcpEnabled { get; set; } - /// Terminal result of the original operation. - [JsonPropertyName("outcome")] - public required McpInstallationOutcome Outcome { get; set; } -} + /// Whether the user is a GitHub/Microsoft staff member. + [JsonPropertyName("is_staff")] + public bool? IsStaff { get; set; } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationResultNegotiationRefused : McpInstallationResult -{ - /// - [JsonIgnore] - public override string Kind => "negotiation-refused"; + /// Per-category quota allotments for free/limited-tier users, keyed by quota category. + [JsonPropertyName("limited_user_quotas")] + public IDictionary? LimitedUserQuotas { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Date the free/limited-tier user's quotas next reset, as a raw string from the Copilot API. + [JsonPropertyName("limited_user_reset_date")] + public string? LimitedUserResetDate { get; set; } - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } + /// GitHub login of the authenticated user. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + /// Per-category monthly quota allotments, keyed by quota category. + [JsonPropertyName("monthly_quotas")] + public IDictionary? MonthlyQuotas { get; set; } - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// Organizations the user belongs to, each with an optional ID, login, and display name. + [JsonPropertyName("organization_list")] + public IList? OrganizationList { get; set; } - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Logins of the organizations the user belongs to. + [JsonPropertyName("organization_login_list")] + public IList? OrganizationLoginList { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// Date the user's usage quota next resets, as a raw string from the Copilot API; see `quota_reset_date_utc` for the UTC-normalized value. + [JsonPropertyName("quota_reset_date")] + public string? QuotaResetDate { get; set; } + + /// UTC-normalized form of `quota_reset_date` (the date the user's usage quota next resets). + [JsonPropertyName("quota_reset_date_utc")] + public string? QuotaResetDateUtc { get; set; } + + /// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. + [JsonPropertyName("quota_snapshots")] + public CopilotUserResponseQuotaSnapshots? QuotaSnapshots { get; set; } + + /// Whether the user's telemetry is subject to restricted-data handling. + [JsonPropertyName("restricted_telemetry")] + public bool? RestrictedTelemetry { get; set; } + + /// Raw passthrough of the Copilot API `te` flag for the user (an opaque server-side eligibility signal surfaced in telemetry); not otherwise interpreted by the runtime. + [JsonPropertyName("te")] + public bool? Te { get; set; } + + /// Whether the account is on usage-based (token/AI-credit) billing rather than a fixed premium-request quota. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. +/// The hmac variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationResultInvalidRequest : McpInstallationResult +public partial class AuthInfoHmac : AuthInfo { /// [JsonIgnore] - public override string Kind => "invalid-request"; + public override string Type => "hmac"; - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// HMAC secret used to sign requests. + [JsonPropertyName("hmac")] + public required string Hmac { get; set; } + + /// Authentication host. HMAC auth always targets the public GitHub host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// Applies exactly one previously prepared operation on its original connection. +/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. +/// The env variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpApplyInstallRequest +public partial class AuthInfoEnv : AuthInfo { - /// Capabilities required by the original prepared operation. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Type => "env"; - /// Runtime-issued ID already returned by prepareInstall, never reused or rebound. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Same existing attached or privately borrowed session as preparation. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} + /// Name of the environment variable the token was sourced from. + [JsonPropertyName("envVar")] + public required string EnvVar { get; set; } -/// Read-only preparation of one owned removal under fresh selected-session authority. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPlanUninstallRequest -{ - /// Required authenticated bound installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Authentication host (e.g. https://github.com or a GHES host). + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Exact receipt to inspect, not a server-name guess. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Existing selected session on the original connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// One-use application of the exact retained removal plan. +/// Authentication-info input variant for SDK-configured token authentication, carrying host and the secret token value. +/// The token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpApplyUninstallRequest +public partial class AuthInfoToken : AuthInfo { - /// Required authenticated bound installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Type => "token"; - /// Opaque original removal plan, consumed once. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Same existing selected session as removal preparation. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } -/// User-configured MCP servers, keyed by server name. + /// Opaque native GitHub credential registration backing this token identity, when applicable. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("registrationId")] + public string? RegistrationId { get; set; } + + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } +} + +/// Authentication-info variant backed by an SDK GitHub token callback. It carries routing metadata but never a plaintext token. +/// The token-provider variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpConfigList +public partial class AuthInfoTokenProvider : AuthInfo { - /// All MCP servers from user config, keyed by name. - [JsonPropertyName("servers")] - public IDictionary Servers { get => field ??= new Dictionary(); set; } + /// + [JsonIgnore] + public override string Type => "token-provider"; + + /// Snapshot of the authenticated user's Copilot subscription info, if known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } + + /// Opaque SDK callback registration identifier. + [JsonPropertyName("registrationId")] + public required string RegistrationId { get; set; } } -/// MCP server name and configuration to add to user configuration. +/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. +/// The copilot-api-token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigAddRequest +public partial class AuthInfoCopilotApiToken : AuthInfo { - /// MCP server configuration (stdio process or remote HTTP/SSE). - [JsonPropertyName("config")] - public JsonElement Config { get; set; } + /// + [JsonIgnore] + public override string Type => "copilot-api-token"; - /// Unique name for the MCP server. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("name")] - public string Name { get; set; } = string.Empty; + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host (always the public GitHub host). + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// MCP server name and replacement configuration to write to user configuration. +/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. +/// The user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigUpdateRequest +public partial class AuthInfoUser : AuthInfo { - /// MCP server configuration (stdio process or remote HTTP/SSE). - [JsonPropertyName("config")] - public JsonElement Config { get; set; } + /// + [JsonIgnore] + public override string Type => "user"; - /// Name of the MCP server to update. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("name")] - public string Name { get; set; } = string.Empty; + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } + + /// OAuth user login. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// MCP server name to remove from user configuration. +/// An interactive account whose model provider owns its credentials. It carries no GitHub credential. +/// The account variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigRemoveRequest +public partial class AuthInfoAccount : AuthInfo { - /// OAuth Client ID Metadata Document URL whose persisted credentials should also be removed. - [JsonPropertyName("authClientIdMetadataUrl")] - public string? AuthClientIdMetadataUrl { get; set; } + /// + [JsonIgnore] + public override string Type => "account"; - /// Name of the MCP server to remove. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("name")] - public string Name { get; set; } = string.Empty; + /// Host coordinate owned by the account's model provider. + [JsonPropertyName("host")] + public required string Host { get; set; } + + /// Login identifying the provider-owned account. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// MCP server names to enable for new sessions. +/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. +/// The gh-cli variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigEnableRequest +public partial class AuthInfoGhCli : AuthInfo { - /// 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. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Type => "gh-cli"; + + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } + + /// User login as reported by `gh auth status`. + [JsonPropertyName("login")] + public required string Login { get; set; } + + /// The token returned by `gh auth token`. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// MCP server names to disable for new sessions. +/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. +/// The api-key variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigDisableRequest +public partial class AuthInfoApiKey : AuthInfo { - /// 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. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Type => "api-key"; + + /// The API key. Treat as a secret. + [JsonPropertyName("apiKey")] + public required string ApiKey { get; set; } + + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// New-work inventory or recovery request under an explicitly selected existing session. +/// Current authentication state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpInstallationsRequest +public sealed class AccountGetCurrentAuthResult { - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Authentication errors from the last auth attempt, if any. + [JsonPropertyName("authErrors")] + public IList? AuthErrors { get; set; } - /// Existing selected local session on this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Current authentication information, if authenticated. + [JsonPropertyName("authInfo")] + public AuthInfo? AuthInfo { get; set; } } -/// Existing-operation control. A new session selector is deliberately not accepted. +/// Authenticated account entry returned by `account.getAllUsers`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpInstallationOperationRequest +public sealed class AccountAllUsers { - /// Original installation wire capability; new-work authentication is not reacquired. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Authentication information for this user. + [JsonPropertyName("authInfo")] + public AuthInfo AuthInfo { get => field ??= new(); set; } - /// Exact runtime-issued operation ID on the original connection. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Opaque identifier accepted by account and model selection APIs. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } + + /// Associated token, if available. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// Installed plugin that contributes a discovered extension. +/// Result of a successful login; throws on failure. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredExtensionPlugin +public sealed class AccountLoginResult { - /// Installed plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether the credential was persisted to a secure store (system keychain, or the config file when plaintext storage is enabled). False when no secure store was available and the token was not saved, so the consumer can decide how to proceed. + [JsonPropertyName("storedInVault")] + public bool StoredInVault { get; set; } } -/// Discovered extension metadata and persistent enablement state. +/// Credentials to validate and store. Omit login to resolve the authenticated user from the token. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredExtension +internal sealed class AccountLoginRequest { - /// Whether this extension's persistent per-ID preference is enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Source-qualified ID accepted by both server and session extension enablement methods. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Human-readable extension name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// GitHub host URL. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Absolute path to the extension entry module, suitable for revealing it in a file manager. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// User login/username. When omitted, the runtime validates the token and resolves the login from GitHub. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Containing plugin metadata for plugin-contributed extensions. - [JsonPropertyName("plugin")] - public DiscoveredExtensionPlugin? Plugin { get; set; } + /// GitHub authentication token. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; +} - /// Discovery source. - [JsonPropertyName("source")] - public DiscoveredExtensionSource Source { get; set; } +/// Logout result indicating if more users remain. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AccountLogoutResult +{ + /// Whether other authenticated users remain after logout. + [JsonPropertyName("hasMoreUsers")] + public bool HasMoreUsers { get; set; } } -/// Extensions discovered from persisted Copilot home state and their effective loading mode. Launch-scoped additional plugins are not included. +/// User to log out. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredExtensions +internal sealed class AccountLogoutRequest { - /// Discovered user and enabled installed-plugin extensions from persisted Copilot home state. - [JsonPropertyName("extensions")] - public IList Extensions { get => field ??= []; set; } + /// Authentication information for the user to log out. + [JsonPropertyName("authInfo")] + public AuthInfo? AuthInfo { get; set; } - /// Effective extension loading mode. Defaults to load_and_augment when unset. - [JsonPropertyName("mode")] - public DiscoveredExtensionMode Mode { get; set; } + /// Opaque account identifier returned by `account.getAllUsers`. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } } -/// Source-qualified extension identifiers to persistently enable for future sessions. +/// The wording the runtime uses for an authentication identity. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiscoveredExtensionsEnableRequest +internal sealed class AccountDescribeAuthInfoResult { - /// Source-qualified user or plugin extension IDs to enable. - [JsonPropertyName("ids")] - public IList Ids { get => field ??= []; set; } + /// One-line description of the identity, suitable after a verb such as "Switched to". + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Sign-in banner announcing the authenticated user. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// Source-qualified extension identifiers to persistently disable for future sessions. +/// Credential-free authentication identity safe to expose to hosts and user interfaces. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiscoveredExtensionsDisableRequest +public sealed class AuthIdentity { - /// Source-qualified user or plugin extension IDs to disable. - [JsonPropertyName("ids")] - public IList Ids { get => field ??= []; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Name of the environment variable that supplied the credential, when applicable. + [JsonPropertyName("envVar")] + public string? EnvVar { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// Authenticated login, when available. + [JsonPropertyName("login")] + public string? Login { get; set; } + + /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. + [JsonPropertyName("registrationId")] + public string? RegistrationId { get; set; } + + /// Authentication type. + [JsonPropertyName("type")] + public AuthInfoType Type { get; set; } } -/// Skill installation management result with the honoured contract, or a typed refusal. -/// Polymorphic base type discriminated by kind. +/// The authentication identity whose shared wording should be rendered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationManagementResultOutcome), "outcome")] -[JsonDerivedType(typeof(SkillInstallationManagementResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(SkillInstallationManagementResultInvalidRequest), "invalid-request")] -public partial class SkillInstallationManagementResult +internal sealed class AccountDescribeAuthInfoRequest { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Identity to describe. + [JsonPropertyName("identity")] + public AuthIdentity Identity { get => field ??= new(); set; } } - -/// Management outcome for verified Skill inventory, planning and removal. -/// Polymorphic base type discriminated by kind. +/// Whether the identity can create gists, and why not when it cannot. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeInstallPlanned), "install-planned")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeListed), "listed")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecovered), "recovered")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRolledBack), "rolled-back")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeOperation), "operation")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeEnabledChanged), "enabled-changed")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRefused), "refused")] -public partial class SkillInstallationManagementOutcome +internal sealed class AccountGetGistSupportResult { - /// The type discriminator. + /// Machine-readable reason category when unsupported. [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + public string? Kind { get; set; } + /// Human-readable explanation to show where the gist action would have been. + [JsonPropertyName("reason")] + public string? Reason { get; set; } -/// Already-confirmed durable work must be reconciled before new mutations or inventory. -/// The recovery-required variant of . + /// True when the identity can create gists. + [JsonPropertyName("supported")] + public bool Supported { get; set; } +} + +/// The authentication identity whose gist support should be reported. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRecoveryRequired : SkillInstallationManagementOutcome +internal sealed class AccountGetGistSupportRequest { - /// - [JsonIgnore] - public override string Kind => "recovery-required"; + /// Identity to evaluate. + [JsonPropertyName("identity")] + public AuthIdentity Identity { get => field ??= new(); set; } } -/// Safe verified Skill review fields. No raw credential, candidate handle or plan handle. -/// Polymorphic base type discriminated by action. +/// An absolute URL on the identity's GitHub host. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "action", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationReviewInstall), "install")] -[JsonDerivedType(typeof(SkillInstallationReviewUninstall), "uninstall")] -public partial class SkillInstallationReview +internal sealed class AccountGetWebUrlResult { - /// The type discriminator. - [JsonPropertyName("action")] - public virtual string Action { get; set; } = string.Empty; + /// Absolute URL for the requested path. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } - -/// One reviewed Skill file. +/// A path to resolve against the GitHub host an identity is signed in to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationFileReview +internal sealed class AccountGetWebUrlRequest { - /// SHA-256 digest of the exact file bytes. - [JsonPropertyName("digest")] - public string Digest { get; set; } = string.Empty; - - /// Whether the file is installed with executable permissions. - [JsonPropertyName("executable")] - public bool Executable { get; set; } - - /// Declared media type for the file. - [JsonPropertyName("mediaType")] - public string MediaType { get; set; } = string.Empty; + /// Identity whose host the path resolves against. Omit to resolve against the public github.com host. + [JsonPropertyName("identity")] + public AuthIdentity? Identity { get; set; } - /// Relative file path within the Skill root. + /// Host-relative path, without a leading slash, for example `settings/copilot/features`. + [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("path")] public string Path { get; set; } = string.Empty; - - /// Exact reviewed file size in bytes. - [JsonPropertyName("sizeBytes")] - public long SizeBytes { get; set; } } -/// Source identity retained from Agent Finder and the pinned GitHub descriptor. +/// The environment variable supplying a classic personal access token, when one is set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationSource +internal sealed class AccountGetTokenEnvVarResult { - /// Digest of the descriptor's bundle manifest. - [JsonPropertyName("bundleDigest")] - public string BundleDigest { get; set; } = string.Empty; + /// Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. + [JsonPropertyName("name")] + public string? Name { get; set; } +} - /// Agent Finder materialisation revision identifier. - [JsonPropertyName("catalogRevisionId")] - public string CatalogRevisionId { get; set; } = string.Empty; +/// Confirmation that the secret values were registered. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SecretsAddFilterValuesResult +{ + /// Whether the values were successfully registered. + [JsonPropertyName("ok")] + public bool Ok { get; set; } +} - /// Digest of the canonical materialisation descriptor. - [JsonPropertyName("descriptorDigest")] - public string DescriptorDigest { get; set; } = string.Empty; +/// Secret values to add to the redaction filter. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SecretsAddFilterValuesRequest +{ + /// Raw secret values to register for redaction. + [JsonPropertyName("values")] + public IList Values { get => field ??= []; set; } +} - /// Repository full name, for example owner/name. - [JsonPropertyName("repository")] - public string Repository { get; set; } = string.Empty; +/// Concrete configuration file containing an MCP server declaration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpSourceFile +{ + /// RFC 6901 JSON Pointer to the server declaration, when known. + [JsonPropertyName("jsonPointer")] + public string? JsonPointer { get; set; } - /// GitHub repository database identifier. - [JsonPropertyName("repositoryId")] - public string RepositoryId { get; set; } = string.Empty; + /// Canonical file URI for the configuration document. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; +} - /// Agent Finder resource identifier. - [JsonPropertyName("resourceId")] - public string ResourceId { get; set; } = string.Empty; +/// Plugin identity associated with an MCP server declaration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpSourcePlugin +{ + /// Canonical plugin identity. + [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("id")] + public string Id { get; set; } = string.Empty; - /// Pinned Git commit revision. - [JsonPropertyName("revision")] - public string Revision { get; set; } = string.Empty; + /// Human-readable plugin name, when available. + [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("name")] + public string? Name { get; set; } - /// Root path within the pinned repository. - [JsonPropertyName("root")] - public string Root { get; set; } = string.Empty; + /// Plugin version, when available. + [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("version")] + public string? Version { get; set; } } -/// A user-facing personal Skill installation location without absolute host paths. +/// Canonical identity and location of the effective MCP server declaration. The declaration is uniquely addressed by this source id together with the discovered server name. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationLocation +public sealed class McpSourceRef { - /// Diagnostics-only absolute host path. Hosts must not display it by default. - [JsonPropertyName("diagnosticsAbsolutePath")] - public string? DiagnosticsAbsolutePath { get; set; } + /// Open semantic editability identifier. Known values are editable and read-only. + [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("editability")] + public string Editability { get; set; } = string.Empty; - /// Safe display label, for example ~/.copilot/skills/run-checks. - [JsonPropertyName("displayLabel")] - public string DisplayLabel { get; set; } = string.Empty; + /// Configuration file location, when the declaration is file-backed. + [JsonPropertyName("file")] + public McpSourceFile? File { get; set; } - /// Path relative to the Copilot home. - [JsonPropertyName("relativePath")] - public string RelativePath { get; set; } = string.Empty; + /// Opaque stable identity for the configuration source. Clients must not parse this value. + [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("id")] + public string Id { get; set; } = string.Empty; - /// Installation scope. Agent Finder Skills are installed in the user's personal Copilot home. - [JsonPropertyName("scope")] - public SkillInstallationScope Scope { get; set; } + /// Open source-kind identifier. Known values include user, workspace, invocation, plugin, builtin, and device-registry. + [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("kind")] + public string Kind { get; set; } = string.Empty; + + /// Plugin identity, when the declaration is plugin-provided. + [JsonPropertyName("plugin")] + public McpSourcePlugin? Plugin { get; set; } } -/// Review for installing a verified Skill. -/// The install variant of . +/// MCP server discovered by `mcp.discover`, with config source, optional plugin source, transport type, and enabled state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationReviewInstall : SkillInstallationReview +public sealed class DiscoveredMcpServer { - /// - [JsonIgnore] - public override string Action => "install"; + /// Canonical identity and location of the effective server declaration. + [JsonPropertyName("effectiveSource")] + public McpSourceRef? EffectiveSource { get; set; } - /// Catalogue identity retained from the bound candidate before consent. - [JsonPropertyName("catalogue")] - public required InstallationCatalogueIdentity Catalogue { get; set; } - - /// Skill description from SKILL.md when present. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// - /// Complete verified SKILL.md content. Planning refuses with review-too-large - /// when this exceeds 262144 UTF-8 bytes; it is never truncated. - /// - [JsonPropertyName("entrypointContent")] - public required string EntrypointContent { get; set; } - - /// Relative path of the verified Skill entrypoint. - [JsonPropertyName("entrypointPath")] - public required string EntrypointPath { get; set; } - - /// Reviewed files and digests. - [JsonPropertyName("files")] - public required IList Files { get; set; } - - /// Installing never grants immediate use; the Skill is written disabled. - [JsonPropertyName("installsDisabled")] - public required bool InstallsDisabled { get; set; } + /// Whether the server is enabled (not in the disabled list). + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Skill invocation name from SKILL.md. + /// Server name (config key). + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("name")] - public required string Name { get; set; } + public string Name { get; set; } = string.Empty; - /// Exact verified source identity. + /// Configuration source: user, workspace, plugin, or builtin. [JsonPropertyName("source")] - public required SkillInstallationSource Source { get; set; } + public McpServerSource Source { get; set; } - /// Exact user-scope target location without an absolute host path. - [JsonPropertyName("target")] - public required SkillInstallationLocation Target { get; set; } + /// Plugin name that provided this server, when source is plugin. + [JsonPropertyName("sourcePlugin")] + public string? SourcePlugin { get; set; } - /// Total reviewed payload size in bytes. - [JsonPropertyName("totalBytes")] - public required long TotalBytes { get; set; } + /// Plugin version that provided this server, when source is plugin. + [JsonPropertyName("sourcePluginVersion")] + public string? SourcePluginVersion { get; set; } + + /// Server transport type: stdio, http, sse (deprecated), or memory. + [JsonPropertyName("type")] + public DiscoveredMcpServerType? Type { get; set; } } -/// Durable verified Skill ownership summary. +/// MCP servers discovered from user, workspace, plugin, and built-in sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationSummary +public sealed class McpDiscoverResult { - /// Catalogue identity retained at install time. - [JsonPropertyName("catalogue")] - public InstallationCatalogueIdentity Catalogue { get => field ??= new(); set; } - - /// Persisted enablement requested for this installation. - [JsonPropertyName("configuredEnabled")] - public bool ConfiguredEnabled { get; set; } - - /// Exact durable installation receipt identity. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; - - /// ISO 8601 wall-clock installation time. - [JsonPropertyName("installedAt")] - public string InstalledAt { get; set; } = string.Empty; - - /// Skill invocation name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Operation that installed this Skill. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; - - /// Ownership state observed from files and receipts. - [JsonPropertyName("ownershipState")] - public SkillInstallationOwnershipState OwnershipState { get; set; } - - /// Bound-session load observation. - [JsonPropertyName("sessionState")] - public SkillInstallationSessionState SessionState { get; set; } - - /// Exact retained verified source identity. - [JsonPropertyName("source")] - public SkillInstallationSource Source { get => field ??= new(); set; } - - /// User-facing installation location without an absolute host path. - [JsonPropertyName("target")] - public SkillInstallationLocation Target { get => field ??= new(); set; } + /// MCP servers discovered from all sources. + [JsonPropertyName("servers")] + public IList Servers { get => field ??= []; set; } } -/// Review for uninstalling an owned verified Skill. -/// The uninstall variant of . +/// Optional working directory used as context for MCP server discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationReviewUninstall : SkillInstallationReview +internal sealed class McpDiscoverRequest { - /// - [JsonIgnore] - public override string Action => "uninstall"; - - /// Catalogue identity retained at install time. - [JsonPropertyName("catalogue")] - public required InstallationCatalogueIdentity Catalogue { get; set; } - - /// Files recorded by the installation receipt. - [JsonPropertyName("files")] - public required IList Files { get; set; } - - /// Whether current files differ from the receipt. Apply refuses drift. - [JsonPropertyName("filesModified")] - public required bool FilesModified { get; set; } - - /// Owned installation being removed. - [JsonPropertyName("installation")] - public required SkillInstallationSummary Installation { get; set; } + /// Whether to include canonical effectiveSource metadata for each discovered server. Callers must opt in so protocol-3 clients retain the legacy closed response shape. + [JsonPropertyName("includeEffectiveSource")] + public bool? IncludeEffectiveSource { get; set; } - /// Total receipt-owned payload size in bytes. - [JsonPropertyName("totalBytes")] - public required long TotalBytes { get; set; } + /// Working directory used as context for discovery (e.g., plugin resolution). + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// A computed Skill install plan. Nothing has been applied. +/// Names of the MCP servers the runtime supplies itself. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallPlan +internal sealed class McpListBuiltinServerNamesResult { - /// Original wall-clock expiry as an ISO 8601 timestamp. - [JsonPropertyName("expiresAt")] - public string ExpiresAt { get; set; } = string.Empty; - - /// Original operation identifier returned before confirmation. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; - - /// One-use plan handle, bound to the original candidate authority. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; - - /// Safe review to present before applying the plan. - [JsonPropertyName("review")] - public SkillInstallationReview Review { get => field ??= new(); set; } + /// Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } } -/// A verified Skill installation plan was prepared. -/// The install-planned variant of . +/// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeInstallPlanned : SkillInstallationManagementOutcome +internal sealed class McpShouldExcludeGitHubToolsResult { - /// - [JsonIgnore] - public override string Kind => "install-planned"; - - /// Prepared install plan. - [JsonPropertyName("plan")] - public required SkillInstallPlan Plan { get; set; } + /// True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. + [JsonPropertyName("excludeGhReplaceableTools")] + public bool ExcludeGhReplaceableTools { get; set; } } -/// Owned Skill installations were listed. -/// The listed variant of . +/// The session tool filters that decide whether the session still has a shell to run `gh` with. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeListed : SkillInstallationManagementOutcome +internal sealed class McpShouldExcludeGitHubToolsRequest { - /// - [JsonIgnore] - public override string Kind => "listed"; + /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + [JsonPropertyName("availableTools")] + public IList? AvailableTools { get; set; } - /// Owned Skill installation summaries. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } + /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + [JsonPropertyName("excludedTools")] + public IList? ExcludedTools { get; set; } + + /// How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + [JsonPropertyName("toolFilterPrecedence")] + public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; } } -/// Recovery completed and inventory was inspected. -/// The recovered variant of . +/// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRecovered : SkillInstallationManagementOutcome +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpPlanInstallResultPlanned), "planned")] +[JsonDerivedType(typeof(McpPlanInstallResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(McpPlanInstallResultHandleRejected), "handle-rejected")] +[JsonDerivedType(typeof(McpPlanInstallResultInvalidRequest), "invalid-request")] +[JsonDerivedType(typeof(McpPlanInstallResultAuthenticationRequired), "authentication-required")] +[JsonDerivedType(typeof(McpPlanInstallResultPolicyRejected), "policy-rejected")] +[JsonDerivedType(typeof(McpPlanInstallResultNetworkFailure), "network-failure")] +[JsonDerivedType(typeof(McpPlanInstallResultUnsafeRetrieval), "unsafe-retrieval")] +[JsonDerivedType(typeof(McpPlanInstallResultMalformedCard), "malformed-card")] +[JsonDerivedType(typeof(McpPlanInstallResultContractViolation), "contract-violation")] +[JsonDerivedType(typeof(McpPlanInstallResultUnavailableTransport), "unavailable-transport")] +[JsonDerivedType(typeof(McpPlanInstallResultNotInstallable), "not-installable")] +[JsonDerivedType(typeof(McpPlanInstallResultUnavailable), "unavailable")] +public partial class McpPlanInstallResult { - /// - [JsonIgnore] - public override string Kind => "recovered"; - - /// Owned Skill installation summaries after recovery. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Interrupted work was safely compensated and the pending marker was cleared. -/// The rolled-back variant of . + +/// The protocol version and capability set the runtime actually honoured for a successful catalog operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRolledBack : SkillInstallationManagementOutcome +public sealed class CatalogNegotiatedContract { - /// - [JsonIgnore] - public override string Kind => "rolled-back"; - - /// Original operation identity. - [JsonPropertyName("operation_id")] - public required string OperationId { get; set; } + /// Wire features the runtime understood for this operation. Includes the five original catalog capabilities and only explicitly requested supported additions, in supported order without duplicates. Capabilities that introduce new success-union variants or operations are therefore included only when explicitly required, preserving older protocol-v3 clients. Always a superset of the caller's required features, because any shortfall is a refusal instead. Operation availability remains a separate typed result. + [JsonPropertyName("grantedCapabilities")] + public IList GrantedCapabilities { get => field ??= []; set; } - /// Cause of the compensation. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } + /// Protocol version of the runtime that served the request. + [JsonPropertyName("runtimeProtocolVersion")] + public long RuntimeProtocolVersion { get; set; } } -/// A computed Skill uninstall plan. Nothing has been removed. +/// The configuration-change alternative for the transportChoices entry at the same index. Only the selected alternative is applied; entries are not cumulative. The payload stays behind the runtime boundary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillUninstallPlan +public sealed class McpPlanConfigurationChange { - /// Original wall-clock expiry as an ISO 8601 timestamp. - [JsonPropertyName("expiresAt")] - public string ExpiresAt { get; set; } = string.Empty; + /// Names of the configuration fields the change would set, without their values. + [JsonPropertyName("changedFields")] + public IList ChangedFields { get => field ??= []; set; } - /// Owned Skill installation being removed. - [JsonPropertyName("installation")] - public SkillInstallationSummary Installation { get => field ??= new(); set; } + /// Configuration key the change applies to. + [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("configKey")] + public string ConfigKey { get; set; } = string.Empty; - /// Original removal operation identifier returned before confirmation. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Whether the change would create a new entry or modify an existing one. + [JsonPropertyName("operation")] + public McpPlanConfigurationOperation Operation { get; set; } - /// One-use uninstall plan handle. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Scope the change would be written to. + [JsonPropertyName("scope")] + public McpPlanScope Scope { get; set; } - /// Safe review to present before applying removal. - [JsonPropertyName("review")] - public SkillInstallationReview Review { get => field ??= new(); set; } + /// Secret placeholders the written configuration would reference. The constrained placeholder type cannot carry a literal secret value. + [JsonPropertyName("secretReferences")] + public IList SecretReferences { get => field ??= []; set; } } -/// An owned Skill uninstall plan was prepared. -/// The uninstall-planned variant of . +/// Normalised identity of the MCP server a plan targets, independent of how the card spelled it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeUninstallPlanned : SkillInstallationManagementOutcome +public sealed class McpPlanResourceIdentity { - /// - [JsonIgnore] - public override string Kind => "uninstall-planned"; + /// Canonical, normalised name of the server, for example `io.github.owner/server`. + [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("canonicalName")] + public string CanonicalName { get; set; } = string.Empty; - /// Prepared uninstall plan. - [JsonPropertyName("plan")] - public required SkillUninstallPlan Plan { get; set; } -} + /// Registry identifier of the server, when it came from a registry. + [JsonPropertyName("registryId")] + public string? RegistryId { get; set; } -/// Status snapshot from the original connection, independent of new-work account availability. -/// Polymorphic base type discriminated by phase. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "phase", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationOperationStatusPreparing), "preparing")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusPrepared), "prepared")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusRevalidating), "revalidating")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusApplying), "applying")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusCompleted), "completed")] -public partial class SkillInstallationOperationStatus -{ - /// The type discriminator. - [JsonPropertyName("phase")] - public virtual string Phase { get; set; } = string.Empty; -} + /// Local configuration key the server would be recorded under. + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + /// Version advertised by the card, when it declares one. + [JsonPropertyName("version")] + public string? Version { get; set; } +} -/// Original operation progress discriminator. -/// The preparing variant of . +/// Outcome of evaluating the planned server against registry and enterprise policy. Evaluation is read-only. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusPreparing : SkillInstallationOperationStatus +public sealed class McpPlanPolicyResult { - /// - [JsonIgnore] - public override string Phase => "preparing"; + /// What policy decided for this server. + [JsonPropertyName("decision")] + public McpPlanPolicyDecision Decision { get; set; } - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("reason")] + public string? Reason { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Which authority produced the decision. + [JsonPropertyName("source")] + public McpPlanPolicySource Source { get; set; } } -/// Original operation progress discriminator. -/// The prepared variant of . +/// Semantic digest of a strictly parsed and schema-validated JSON MCP card. Both URL-backed and embedded cards are canonicalised with RFC 8785 JSON Canonicalization Scheme, encoded as UTF-8, and hashed with SHA-256. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusPrepared : SkillInstallationOperationStatus +public sealed class CardDigest { - /// - [JsonIgnore] - public override string Phase => "prepared"; - - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Digest algorithm and canonical representation. + [JsonPropertyName("algorithm")] + public CardDigestAlgorithm Algorithm { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// SHA-256 digest of the RFC 8785 canonical UTF-8 bytes, encoded as exactly 64 lowercase hexadecimal characters. + [RegularExpression("^[0-9a-f]{64}$")] + [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(64)] + [MaxLength(64)] + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; } -/// Original operation progress discriminator. -/// The awaiting-confirmation variant of . +/// Provenance of the exact validated JSON MCP card content bound privately to a completed plan and its opaque handle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusAwaitingConfirmation : SkillInstallationOperationStatus +public sealed class McpPlanProvenance { - /// - [JsonIgnore] - public override string Phase => "awaiting-confirmation"; + /// Authority associated with the validated card, without path, query, or credentials. Inert untrusted data. + [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("authority")] + public string Authority { get; set; } = string.Empty; - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Semantic digest of the exact validated JSON content bound to the plan handle. + [JsonPropertyName("cardDigest")] + public CardDigest CardDigest { get => field ??= new(); set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// JSON MCP media type the validated card was interpreted as. + [JsonPropertyName("mediaType")] + public McpServerCardMediaType MediaType { get; set; } + + /// ISO 8601 timestamp at which the runtime completed strict parsing and schema validation of the card content. + [JsonPropertyName("validatedAt")] + public string ValidatedAt { get; set; } = string.Empty; } -/// Original operation progress discriminator. -/// The revalidating variant of . +/// Where a plan would be written. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusRevalidating : SkillInstallationOperationStatus +public sealed class McpPlanTarget { - /// - [JsonIgnore] - public override string Phase => "revalidating"; - - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Configuration key the server would be recorded under within that scope. + [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("configKey")] + public string ConfigKey { get; set; } = string.Empty; - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Configuration scope the plan targets. + [JsonPropertyName("scope")] + public McpPlanScope Scope { get; set; } } -/// Original operation progress discriminator. -/// The applying variant of . +/// One eligible way to run the server, represented as a tagged package or remote variant so package identity and endpoint states cannot contradict the install method. +/// Polymorphic base type discriminated by installMethod. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusApplying : SkillInstallationOperationStatus +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "installMethod", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpPlanTransportChoicePackage), "package")] +[JsonDerivedType(typeof(McpPlanTransportChoiceRemote), "remote")] +public partial class McpPlanTransportChoice { - /// - [JsonIgnore] - public override string Phase => "applying"; - - /// Whether cancellation has been requested; already-started effects require recovery. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } - - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// The type discriminator. + [JsonPropertyName("installMethod")] + public virtual string InstallMethod { get; set; } = string.Empty; } -/// Terminal verified Skill mutation result. + +/// One non-secret value a transport choice needs, represented as a scalar or enumerated variant so enum values cannot be missing or attached to another type. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationOutcomeInstalled), "installed")] -[JsonDerivedType(typeof(SkillInstallationOutcomeUninstalled), "uninstalled")] -[JsonDerivedType(typeof(SkillInstallationOutcomeRolledBack), "rolled-back")] -[JsonDerivedType(typeof(SkillInstallationOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(SkillInstallationOutcomeDeclined), "declined")] -[JsonDerivedType(typeof(SkillInstallationOutcomeCancelled), "cancelled")] -[JsonDerivedType(typeof(SkillInstallationOutcomeRefused), "refused")] -public partial class SkillInstallationOutcome +[JsonDerivedType(typeof(McpPlanRequiredValueScalar), "scalar")] +[JsonDerivedType(typeof(McpPlanRequiredValueEnum), "enum")] +public partial class McpPlanRequiredValue { /// The type discriminator. [JsonPropertyName("kind")] @@ -4671,206 +4670,285 @@ public partial class SkillInstallationOutcome } -/// The verified Skill was installed disabled. -/// The installed variant of . +/// One non-secret scalar value a transport choice needs before it can be applied. +/// The scalar variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeInstalled : SkillInstallationOutcome +public partial class McpPlanRequiredValueScalar : McpPlanRequiredValue { /// [JsonIgnore] - public override string Kind => "installed"; - - /// Durable installed Skill summary. - [JsonPropertyName("installation")] - public required SkillInstallationSummary Installation { get; set; } -} + public override string Kind => "scalar"; -/// The owned Skill was removed. -/// The uninstalled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeUninstalled : SkillInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "uninstalled"; + /// Where the value is applied when the server is launched. + [JsonPropertyName("category")] + public required McpPlanValueCategory Category { get; set; } - /// Removed installation identity. - [JsonPropertyName("installationId")] - public required string InstallationId { get; set; } + /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("defaultValue")] + public string? DefaultValue { get; set; } - /// Original removal operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Human-readable explanation from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } -/// The durable transaction was aborted or fully compensated. -/// The rolled-back variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeRolledBack : SkillInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "rolled-back"; + /// Whether the value may be supplied more than once. + [JsonPropertyName("isRepeated")] + public required bool IsRepeated { get; set; } - /// Original operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Key the value is supplied under. Inert untrusted data. + [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("key")] + public required string Key { get; set; } - /// Cause of the fully aborted or compensated operation. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } -} + /// Whether the value must be present for the plan to be applicable. + [JsonPropertyName("required")] + public required bool Required { get; set; } -/// A write may have completed. Recover and inspect durable state before retrying. -/// The recovery-required variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeRecoveryRequired : SkillInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "recovery-required"; + /// Human-readable label from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("title")] + public string? Title { get; set; } - /// Operation whose durable result must be recovered and inspected. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Scalar type the value must conform to. + [JsonPropertyName("valueType")] + public required McpPlanScalarValueType ValueType { get; set; } } -/// The user declined the confirmation request. -/// The declined variant of . +/// One enumerated non-secret value a transport choice needs before it can be applied. The permitted values are structurally required. +/// The enum variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeDeclined : SkillInstallationOutcome +public partial class McpPlanRequiredValueEnum : McpPlanRequiredValue { /// [JsonIgnore] - public override string Kind => "declined"; + public override string Kind => "enum"; - /// Original operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Where the value is applied when the server is launched. + [JsonPropertyName("category")] + public required McpPlanValueCategory Category { get; set; } -/// The operation was cancelled before a terminal mutation. -/// The cancelled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeCancelled : SkillInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("defaultValue")] + public string? DefaultValue { get; set; } - /// Original operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Human-readable explanation from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } -/// The operation was refused without applying changes. -/// The refused variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeRefused : SkillInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "refused"; + /// Non-empty permitted value set. Inert untrusted data. + [JsonPropertyName("enumValues")] + public required IList EnumValues { get; set; } - /// Present once an operation has been allocated. + /// Whether the value may be supplied more than once. + [JsonPropertyName("isRepeated")] + public required bool IsRepeated { get; set; } + + /// Key the value is supplied under. Inert untrusted data. + [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("key")] + public required string Key { get; set; } + + /// Whether the value must be present for the plan to be applicable. + [JsonPropertyName("required")] + public required bool Required { get; set; } + + /// Human-readable label from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operationId")] - public string? OperationId { get; set; } + [JsonPropertyName("title")] + public string? Title { get; set; } - /// Bounded refusal reason. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } + /// Discriminator: the value must be one of `enumValues`. + [JsonPropertyName("valueType")] + public required McpPlanEnumValueType ValueType { get; set; } } -/// Original operation progress discriminator. -/// The completed variant of . +/// A secret a transport choice needs, referenced by placeholder. No secret value ever appears in a plan, and the placeholder resolves against the keychain only when a plan is applied. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusCompleted : SkillInstallationOperationStatus +public sealed class McpPlanSecretPlaceholder { - /// - [JsonIgnore] - public override string Phase => "completed"; - - /// Whether cancellation was requested before the terminal result. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Key the secret is supplied under. Inert untrusted data. + [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("key")] + public string Key { get; set; } = string.Empty; - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// The runtime-assigned `${secret:<id>}` placeholder written into configuration in place of the value. + [JsonPropertyName("placeholder")] + public string Placeholder { get; set; } = string.Empty; - /// Immutable terminal receipt. - [JsonPropertyName("outcome")] - public required SkillInstallationOutcome Outcome { get; set; } + /// Human-readable label from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("title")] + public string? Title { get; set; } } -/// Original-connection operation snapshot. -/// The operation variant of . +/// An eligible local-package transport choice. Package identity is required and a remote endpoint cannot be represented. +/// The package variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeOperation : SkillInstallationManagementOutcome +public partial class McpPlanTransportChoicePackage : McpPlanTransportChoice { /// [JsonIgnore] - public override string Kind => "operation"; + public override string InstallMethod => "package"; - /// Operation status. - [JsonPropertyName("operation")] - public required SkillInstallationOperationStatus Operation { get; set; } + /// Stable identifier for this choice within the plan, used to select it when the plan is applied. + [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)] + [MaxLength(128)] + [JsonPropertyName("choiceId")] + public required string ChoiceId { get; set; } + + /// Package identifier. Inert untrusted data. + [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)] + [MaxLength(512)] + [JsonPropertyName("packageIdentifier")] + public required string PackageIdentifier { get; set; } + + /// Packaging ecosystem, for example `oci` or `npm`. + [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)] + [MaxLength(64)] + [JsonPropertyName("packageType")] + public required string PackageType { get; set; } + + /// Typed values this choice requires, excluding secrets. + [JsonPropertyName("requiredValues")] + public required IList RequiredValues { get; set; } + + /// Secrets this choice requires, referenced by placeholder only. + [JsonPropertyName("secretPlaceholders")] + public required IList SecretPlaceholders { get; set; } + + /// Local process transport this package choice would use. + [JsonPropertyName("transport")] + public required McpPlanPackageTransport Transport { get; set; } } -/// Enablement changed and the selected session was reconciled. -/// The enabled-changed variant of . +/// An eligible remote-endpoint transport choice. The endpoint is required and package identity cannot be represented. +/// The remote variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeEnabledChanged : SkillInstallationManagementOutcome +public partial class McpPlanTransportChoiceRemote : McpPlanTransportChoice { /// [JsonIgnore] - public override string Kind => "enabled-changed"; + public override string InstallMethod => "remote"; - /// Safe reload or reconciliation diagnostics. - [JsonPropertyName("diagnostics")] - public required IList Diagnostics { get; set; } + /// Stable identifier for this choice within the plan, used to select it when the plan is applied. + [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)] + [MaxLength(128)] + [JsonPropertyName("choiceId")] + public required string ChoiceId { get; set; } - /// Updated installation summary. - [JsonPropertyName("installation")] - public required SkillInstallationSummary Installation { get; set; } + /// Endpoint URL. Inert untrusted data. + [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)] + [MaxLength(2048)] + [JsonPropertyName("endpoint")] + public required string Endpoint { get; set; } + + /// Typed values this choice requires, excluding secrets. + [JsonPropertyName("requiredValues")] + public required IList RequiredValues { get; set; } + + /// Secrets this choice requires, referenced by placeholder only. + [JsonPropertyName("secretPlaceholders")] + public required IList SecretPlaceholders { get; set; } + + /// Endpoint transport this remote choice would use. + [JsonPropertyName("transport")] + public required McpPlanRemoteTransport Transport { get; set; } } -/// The management request was refused. -/// The refused variant of . +/// A normalised, inert description of what installing an MCP server would involve. Carries no raw card, no install specification, and no secret value. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRefused : SkillInstallationManagementOutcome +public sealed class McpInstallPlan { - /// - [JsonIgnore] - public override string Kind => "refused"; + /// Alternative configuration changes, with exactly one entry for each transportChoices entry in the same order. Only the entry for the subsequently selected transport applies; these are not cumulative writes. Payloads remain behind the runtime boundary. + [JsonPropertyName("configurationChanges")] + public IList ConfigurationChanges { get => field ??= []; set; } - /// Bounded refusal reason. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } + /// Normalised identity of the server the plan would install. + [JsonPropertyName("identity")] + public McpPlanResourceIdentity Identity { get => field ??= new(); set; } + + /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this plan. Rejected when stale, replayed, or presented to a different runtime instance. Never logged. + [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("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// ISO 8601 timestamp after which the plan handle is stale and will be rejected. Abandoning a plan needs no call: an unused handle simply expires, so cancellation before commit is side-effect free. + [JsonPropertyName("planHandleExpiresAt")] + public string PlanHandleExpiresAt { get; set; } = string.Empty; + + /// Outcome of evaluating the server against registry and enterprise policy. + [JsonPropertyName("policy")] + public McpPlanPolicyResult Policy { get => field ??= new(); set; } + + /// Origin and semantic digest of the exact validated JSON MCP card content bound to this plan. + [JsonPropertyName("provenance")] + public McpPlanProvenance Provenance { get => field ??= new(); set; } + + /// Identifier of the choice the runtime would pick by default. Omitted when there is no eligible transport, or when the runtime expresses no preference. + [JsonPropertyName("recommendedTransportChoiceId")] + public string? RecommendedTransportChoiceId { get; set; } + + /// Whether applying this plan would require an MCP reload to take effect. Planning itself never reloads. + [JsonPropertyName("reloadRequired")] + public bool ReloadRequired { get; set; } + + /// True only when every eligible transport choice needs additional values or secrets. False means at least one choice needs no additional configuration, not that every choice is ready. A later apply operation must validate the selected choice's own inputs, secrets and policy after explicit confirmation. + [JsonPropertyName("requiresInteractiveConfiguration")] + public bool RequiresInteractiveConfiguration { get; set; } + + /// Configuration scope and key the plan would write to. + [JsonPropertyName("target")] + public McpPlanTarget Target { get => field ??= new(); set; } + + /// Every eligible transport, so a host can present an explicit choice. A completed plan always has at least one; when none is eligible, planning returns `CatalogUnavailableTransportError` instead. + [JsonPropertyName("transportChoices")] + public IList TransportChoices { get => field ??= []; set; } } -/// The outcome variant of . +/// A computed MCP install plan. Nothing has been applied: the plan describes what installing would change, and the plan handle is what a later apply operation would consume. +/// The planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementResultOutcome : SkillInstallationManagementResult +public partial class McpPlanInstallResultPlanned : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "outcome"; + public override string Kind => "planned"; - /// Capabilities honoured for this request. + /// Protocol version and capabilities the runtime honoured. [JsonPropertyName("negotiated")] public required CatalogNegotiatedContract Negotiated { get; set; } - /// Observed management outcome. - [JsonPropertyName("outcome")] - public required SkillInstallationManagementOutcome Outcome { get; set; } + /// The normalised plan. + [JsonPropertyName("plan")] + public required McpInstallPlan Plan { get; set; } } /// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementResultNegotiationRefused : SkillInstallationManagementResult +public partial class McpPlanInstallResultNegotiationRefused : McpPlanInstallResult { /// [JsonIgnore] @@ -4903,10 +4981,34 @@ public partial class SkillInstallationManagementResultNegotiationRefused : Skill public required IList UnsupportedCapabilities { get; set; } } +/// A presented handle was not accepted. Handles are runtime-instance scoped, TTL-bound, and single-use, so each way of failing is reported distinctly. +/// The handle-rejected variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpPlanInstallResultHandleRejected : McpPlanInstallResult +{ + /// + [JsonIgnore] + public override string Kind => "handle-rejected"; + + /// Which kind of handle was presented. + [JsonPropertyName("handleType")] + public required CatalogHandleType HandleType { get; set; } + + /// Human-readable explanation, safe to surface. Never contains the handle itself, nor a query, URL, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why the handle was rejected. + [JsonPropertyName("reason")] + public required CatalogHandleRejectionReason Reason { get; set; } +} + /// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementResultInvalidRequest : SkillInstallationManagementResult +public partial class McpPlanInstallResultInvalidRequest : McpPlanInstallResult { /// [JsonIgnore] @@ -4923,65 +5025,54 @@ public partial class SkillInstallationManagementResultInvalidRequest : SkillInst public required string Message { get; set; } } -/// Side-effect-free planning of one verified Agent Finder Skill candidate. +/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. +/// The authentication-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillPlanInstallRequest +public partial class McpPlanInstallResultAuthenticationRequired : McpPlanInstallResult { - /// Fresh single-use AI skill candidate handle returned by a bound catalogue search. - [JsonPropertyName("candidateHandle")] - public string CandidateHandle { get; set; } = string.Empty; - - /// Required authenticated bound catalogue and Skill installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "authentication-required"; - /// Existing local session attached to this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} + /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } -/// Skill installation result with the honoured contract, or a typed request/negotiation refusal. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationResultOutcome), "outcome")] -[JsonDerivedType(typeof(SkillInstallationResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(SkillInstallationResultInvalidRequest), "invalid-request")] -public partial class SkillInstallationResult -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. + [JsonPropertyName("reason")] + public required CatalogAuthenticationRequiredReason Reason { get; set; } } - -/// The outcome variant of . +/// Registry or enterprise policy refused the operation. +/// The policy-rejected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationResultOutcome : SkillInstallationResult +public partial class McpPlanInstallResultPolicyRejected : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "outcome"; + public override string Kind => "policy-rejected"; - /// Capabilities honoured for this request. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Terminal operation outcome. - [JsonPropertyName("outcome")] - public required SkillInstallationOutcome Outcome { get; set; } + /// Which authority produced the decision. + [JsonPropertyName("source")] + public required McpPlanPolicySource Source { get; set; } } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. +/// The network-failure variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationResultNegotiationRefused : SkillInstallationResult +public partial class McpPlanInstallResultNetworkFailure : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "negotiation-refused"; + public override string Kind => "network-failure"; /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] @@ -4989,307 +5080,305 @@ public partial class SkillInstallationResultNegotiationRefused : SkillInstallati [JsonPropertyName("message")] public required string Message { get; set; } - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } - - /// Whether the version or the capability set was the problem. + /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } - - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + public required CatalogNetworkFailureReason Reason { get; set; } - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("retryAfterSeconds")] + public int? RetryAfterSeconds { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// HTTP status code, when the failure was a rejected response. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("statusCode")] + public int? StatusCode { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. +/// The unsafe-retrieval variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationResultInvalidRequest : SkillInstallationResult +public partial class McpPlanInstallResultUnsafeRetrieval : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "invalid-request"; - - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + public override string Kind => "unsafe-retrieval"; - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MaxLength(1000)] [JsonPropertyName("message")] public required string Message { get; set; } + + /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. + [JsonPropertyName("reason")] + public required CatalogUnsafeRetrievalReason Reason { get; set; } } -/// Applies exactly one retained verified Skill installation plan. +/// A card could not be parsed or did not satisfy its declared media type's schema. +/// The malformed-card variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillApplyInstallRequest +public partial class McpPlanInstallResultMalformedCard : McpPlanInstallResult { - /// Required authenticated bound catalogue and Skill installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "malformed-card"; - /// Opaque original plan, consumed once. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Media type the card was interpreted as, when it declared one this runtime recognises. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mediaType")] + public CatalogMediaType? MediaType { get; set; } - /// Same existing selected session as planning. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// How the card failed validation. + [JsonPropertyName("reason")] + public required CatalogMalformedCardReason Reason { get; set; } } -/// Read-only preparation of one owned Skill removal under fresh selected-session authority. +/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. +/// The contract-violation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillPlanUninstallRequest +public partial class McpPlanInstallResultContractViolation : McpPlanInstallResult { - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "contract-violation"; - /// Exact receipt to inspect. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Existing selected local session on this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Which rule the response broke. + [JsonPropertyName("reason")] + public required CatalogContractViolationReason Reason { get; set; } } -/// One-use application of the exact retained Skill removal plan. +/// No transport this runtime can use is available for the requested server. +/// The unavailable-transport variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillApplyUninstallRequest +public partial class McpPlanInstallResultUnavailableTransport : McpPlanInstallResult { - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "unavailable-transport"; - /// Opaque original removal plan, consumed once. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Same existing selected session as removal preparation. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Why no transport could be offered. + [JsonPropertyName("reason")] + public required CatalogUnavailableTransportReason Reason { get; set; } } -/// Server-side skill metadata, including name, description, source, enabled/invocable state, path, project path, and argument hint. +/// The candidate is discoverable but cannot be installed. `application/ai-skill` resolves here, because it stays searchable while remaining typed non-installable. +/// The not-installable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSkill +public partial class McpPlanInstallResultNotInstallable : McpPlanInstallResult { - /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. - [JsonPropertyName("argumentHint")] - public string? ArgumentHint { get; set; } - - /// Canonical slash command name used to invoke the skill, without the leading '/'. - [JsonPropertyName("commandName")] - public string? CommandName { get; set; } - - /// Description of what the skill does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Whether the skill is currently enabled (based on global config). - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// + [JsonIgnore] + public override string Kind => "not-installable"; - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Absolute path to the skill file. - [JsonPropertyName("path")] - public string? Path { get; set; } + /// Why the candidate cannot be installed. + [JsonPropertyName("reason")] + public required CatalogNotInstallableReason Reason { get; set; } +} - /// The project path this skill belongs to (only for project/inherited skills). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } +/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. +/// The unavailable variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpPlanInstallResultUnavailable : McpPlanInstallResult +{ + /// + [JsonIgnore] + public override string Kind => "unavailable"; - /// Source location type (e.g., project, personal-copilot, plugin, builtin). - [JsonPropertyName("source")] - public SkillSource Source { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Whether the skill can be invoked by the user as a slash command. - [JsonPropertyName("userInvocable")] - public bool UserInvocable { get; set; } + /// Why the operation is unavailable. + [JsonPropertyName("reason")] + public required CatalogUnavailableReason Reason { get; set; } } -/// Skills discovered across global and project sources. +/// The protocol version and capability set a caller requires, supplied on every catalog request so negotiation cannot be skipped by omission. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSkillList +public sealed class CatalogClientContract { - /// Messages for skills that failed to load (e.g. malformed SKILL.md). Empty when host skills are excluded so host-local paths are not disclosed to multitenant callers. - [JsonPropertyName("errors")] - public IList? Errors { get; set; } + /// SDK protocol version the caller was generated against. A caller below the runtime's minimum supported version is refused rather than served a partial result. + [JsonPropertyName("protocolVersion")] + public long ProtocolVersion { get; set; } - /// All discovered skills across all sources. - [JsonPropertyName("skills")] - public IList Skills { get => field ??= []; set; } + /// Wire features the caller requires the runtime to understand. Identifiers are bounded but extensible so a newer caller can negotiate with an older runtime. Requiring an unknown feature yields a typed refusal listing what is understood, never a partial grant. A grant does not promise that a deployment has enabled the operation; typed unavailable results report that separately. + [JsonPropertyName("requiredCapabilities")] + public IList RequiredCapabilities { get => field ??= []; set; } } -/// Optional project paths and additional skill directories to include in discovery. +/// What an install plan is computed from: a candidate handle from a previous search, or a card supplied directly. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsDiscoverRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpPlanInstallSourceCandidate), "candidate")] +[JsonDerivedType(typeof(McpPlanInstallSourceCard), "card")] +public partial class McpPlanInstallSource { - /// When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. - [JsonPropertyName("excludeHostSkills")] - public bool? ExcludeHostSkills { get; set; } - - /// Optional skill scan paths to exclude from discovery. - [JsonPropertyName("ignoredSkillsLocations")] - public IList? IgnoredSkillsLocations { get; set; } - - /// Optional list of project directory paths to scan for project-scoped skills. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } - - /// Optional list of additional skill directory paths to include. - [JsonPropertyName("skillDirectories")] - public IList? SkillDirectories { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Canonical directory where skills can be discovered or created, with scope, preference, and optional project path. + +/// Plan from a candidate returned by a previous catalog search. +/// The candidate variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillDiscoveryPath +public partial class McpPlanInstallSourceCandidate : McpPlanInstallSource { - /// Absolute path of the create/discovery target (may not exist on disk yet). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Whether this is the canonical directory to create a new skill in its tier. At most one entry per tier is preferred; the `personal-agents` and `custom` scopes are never preferred. - [JsonPropertyName("preferredForCreation")] - public bool PreferredForCreation { get; set; } + /// + [JsonIgnore] + public override string Kind => "candidate"; - /// The input project path this directory was derived from (only for project scope). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } + /// Single-use candidate handle. Consumed by this call, so a replay of the same handle is rejected. + [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)] + [MaxLength(256)] + [JsonPropertyName("candidateHandle")] + public required string CandidateHandle { get; set; } - /// Which tier this directory belongs to. - [JsonPropertyName("scope")] - public SkillDiscoveryScope Scope { get; set; } + /// The runtime- or authority-minted `searchId` returned with the search that produced this candidate. Planning verifies the private correlation and atomically consumes a matching candidate before downstream work, including attempts that subsequently fail or report unavailable. A mismatched search does not consume the candidate. It identifies a search rather than a person and must never be joined with user identity to re-identify anyone. + [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)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } } -/// Canonical locations where skills can be created so the runtime will recognize them. +/// A card supplied directly by the caller. Exactly one of a URL or embedded data, encoded structurally so neither both nor neither can be expressed. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillDiscoveryPathList +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpServerCardReferenceUrl), "url")] +[JsonDerivedType(typeof(McpServerCardReferenceEmbedded), "embedded")] +public partial class McpServerCardReference { - /// Canonical skill create/discovery directories, in priority order. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Optional project paths to enumerate. + +/// An MCP server card to be retrieved from a URL through the runtime's hardened fetch boundary. +/// The url variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsGetDiscoveryPathsRequest +public partial class McpServerCardReferenceUrl : McpServerCardReference { - /// When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. - [JsonPropertyName("excludeHostSkills")] - public bool? ExcludeHostSkills { get; set; } + /// + [JsonIgnore] + public override string Kind => "url"; - /// Optional skill scan paths to exclude from discovery. - [JsonPropertyName("ignoredSkillsLocations")] - public IList? IgnoredSkillsLocations { get; set; } + /// Media type the card is expected to conform to. + [JsonPropertyName("mediaType")] + public required McpServerCardMediaType MediaType { get; set; } - /// Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Card URL. Retrieved only through the runtime's hardened boundary, with scheme, credential, address-range, redirect, timeout, and response-size controls applied. Never logged. + [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)] + [MaxLength(2048)] + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// Inventory request under an explicitly selected existing session. +/// An MCP server card supplied inline as an inert document. +/// The embedded variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillInstallationsRequest +public partial class McpServerCardReferenceEmbedded : McpServerCardReference { - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "embedded"; - /// Existing selected local session on this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// The card document verbatim, treated as inert untrusted bytes. The runtime parses and validates it; the host is not expected to interpret it. Never logged. + [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)] + [MaxLength(1048576)] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// Media type the card is expected to conform to. + [JsonPropertyName("mediaType")] + public required McpServerCardMediaType MediaType { get; set; } } -/// Existing-operation control. A new session selector is deliberately not accepted. +/// Plan from a card supplied directly by the caller, without a preceding search. +/// The card variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillInstallationOperationRequest +public partial class McpPlanInstallSourceCard : McpPlanInstallSource { - /// Required authenticated bound Skill installation capability. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "card"; - /// Exact runtime-issued operation ID on the original connection. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// The card to plan from: exactly one of a URL or embedded data. + [JsonPropertyName("card")] + public required McpServerCardReference Card { get; set; } } -/// Persisted enablement update for one owned Skill installation. +/// A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillSetEnabledRequest +public sealed class McpPlanInstallRequest { - /// Required authenticated bound Skill installation capability. + /// Protocol version and capabilities the caller requires. [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } - - /// Persisted enablement value. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Exact receipt identity to update. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + public required CatalogClientContract Contract { get; set; } - /// Existing selected local session to reconcile after persistence. + /// The same existing attached session that owns the original catalogue candidate. + [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)] + [MaxLength(256)] [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} - -/// Skill names to mark as disabled in global configuration, replacing any previous list. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsConfigSetDisabledSkillsRequest -{ - /// List of skill names to disable. - [JsonPropertyName("disabledSkills")] - public IList DisabledSkills { get => field ??= []; set; } -} + public string? PolicySessionId { get; set; } -/// Adds or removes a single skill from the global disabled list, leaving every other entry untouched. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsConfigSetSkillDisabledRequest -{ - /// True to disable the skill, false to enable it. - [JsonPropertyName("disabled")] - public bool Disabled { get; set; } + /// Configuration scope the plan targets. Defaults to user scope when omitted. + [JsonPropertyName("scope")] + public McpPlanScope? Scope { get; set; } - /// Name of the skill to add to or remove from the disabled list. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// What to plan: either a candidate handle from a previous search, or a card supplied directly. + [JsonPropertyName("source")] + public required McpPlanInstallSource Source { get; set; } } -/// Outcome of a catalog.search call: either bounded inert candidates, or one typed refusal. Never a partial success. +/// Management result with contract receipt, or a typed request/negotiation refusal. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogSearchResultSucceeded), "succeeded")] -[JsonDerivedType(typeof(CatalogSearchResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(CatalogSearchResultUnsupportedKind), "unsupported-kind")] -[JsonDerivedType(typeof(CatalogSearchResultInvalidRequest), "invalid-request")] -[JsonDerivedType(typeof(CatalogSearchResultAuthenticationRequired), "authentication-required")] -[JsonDerivedType(typeof(CatalogSearchResultPolicyRejected), "policy-rejected")] -[JsonDerivedType(typeof(CatalogSearchResultNetworkFailure), "network-failure")] -[JsonDerivedType(typeof(CatalogSearchResultUnsafeRetrieval), "unsafe-retrieval")] -[JsonDerivedType(typeof(CatalogSearchResultMalformedCard), "malformed-card")] -[JsonDerivedType(typeof(CatalogSearchResultContractViolation), "contract-violation")] -[JsonDerivedType(typeof(CatalogSearchResultUnavailable), "unavailable")] -public partial class CatalogSearchResult +[JsonDerivedType(typeof(McpInstallationManagementResultOutcome), "outcome")] +[JsonDerivedType(typeof(McpInstallationManagementResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(McpInstallationManagementResultInvalidRequest), "invalid-request")] +public partial class McpInstallationManagementResult { /// The type discriminator. [JsonPropertyName("kind")] @@ -5297,16 +5386,20 @@ public partial class CatalogSearchResult } -/// One inert catalog result, represented as an MCP server, discovery-only AI skill, or opt-in Agent Plugin variant so kind, media type, provenance, and available operations cannot contradict each other. +/// Read-only or recovery management result, never permission to activate or replay. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogCandidateMcpServer), "mcp-server")] -[JsonDerivedType(typeof(CatalogCandidateAiSkill), "ai-skill")] -[JsonDerivedType(typeof(CatalogCandidatePlugin), "plugin")] -public partial class CatalogCandidate +[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeInstallPrepared), "install-prepared")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeListed), "listed")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecovered), "recovered")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeOperation), "operation")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeRefused), "refused")] +public partial class McpInstallationManagementOutcome { /// The type discriminator. [JsonPropertyName("kind")] @@ -5314,856 +5407,699 @@ public partial class CatalogCandidate } -/// Where and when an MCP server catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. +/// Already-confirmed durable work must be reconciled before new mutations or inventory. +/// The recovery-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogMcpServerCandidateProvenance +public partial class McpInstallationManagementOutcomeRecoveryRequired : McpInstallationManagementOutcome { - /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. - [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("authority")] - public string Authority { get; set; } = string.Empty; - - /// JSON MCP media type advertised for the referenced card. - [JsonPropertyName("mediaType")] - public McpServerCardMediaType MediaType { get; set; } - - /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. - [JsonPropertyName("observedAt")] - public string ObservedAt { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "recovery-required"; } -/// Where a candidate's card came from. Exactly one of a URL or embedded data: the union has no variant carrying both, and no variant carrying neither, so the rule holds structurally rather than by validation. -/// Polymorphic base type discriminated by kind. +/// Inert, runtime-owned admission. The operation ID is known before confirmation or effects. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogCandidateSourceUrl), "url")] -[JsonDerivedType(typeof(CatalogCandidateSourceEmbedded), "embedded")] -public partial class CatalogCandidateSource +public sealed class McpPreparedInstall { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Original plan expiry in Unix epoch milliseconds; preparation does not extend it. + [JsonPropertyName("expiresAtEpochMs")] + public long ExpiresAtEpochMs { get; set; } + /// Original connection-owned operation, known before the first confirmation callback. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; +} -/// Candidate whose card is retrieved from a URL through the runtime's hardened fetch boundary. -/// The url variant of . +/// The install-prepared variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateSourceUrl : CatalogCandidateSource +public partial class McpInstallationManagementOutcomeInstallPrepared : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Kind => "url"; + public override string Kind => "install-prepared"; - /// Card URL as advertised. Inert untrusted data: the runtime retrieves it only through its own hardened boundary, and it is never logged. - [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("url")] - public required string Url { get; set; } + /// Known original operation identity, returned before callback or effects. + [JsonPropertyName("operation")] + public required McpPreparedInstall Operation { get; set; } } -/// Candidate whose card reference arrived inline. The document and its content-derived properties stay behind the runtime boundary. -/// The embedded variant of . +/// A versioned, bounded trust observation carried unchanged with a catalog candidate and its private handle context. Current observations require a recognised T1/T2 tier; every non-current state structurally forbids a tier. Eligibility remains `unknown` while Agent Finder supplies no exposure decision, and states absent from its current wire are never inferred from age, relevance, popularity, or a tier transition. +/// Polymorphic base type discriminated by status. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateSourceEmbedded : CatalogCandidateSource +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "status", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogTrustSnapshotCurrent), "current")] +[JsonDerivedType(typeof(CatalogTrustSnapshotAbsent), "absent")] +[JsonDerivedType(typeof(CatalogTrustSnapshotStale), "stale")] +[JsonDerivedType(typeof(CatalogTrustSnapshotDowngraded), "downgraded")] +[JsonDerivedType(typeof(CatalogTrustSnapshotRevoked), "revoked")] +[JsonDerivedType(typeof(CatalogTrustSnapshotUnsupported), "unsupported")] +[JsonDerivedType(typeof(CatalogTrustSnapshotMalformed), "malformed")] +public partial class CatalogTrustSnapshot { - /// - [JsonIgnore] - public override string Kind => "embedded"; + /// The type discriminator. + [JsonPropertyName("status")] + public virtual string Status { get; set; } = string.Empty; } -/// An inert MCP server catalog result. Every free-text field is untrusted external data and must never be treated as an instruction, and the handle is the only way to refer to the candidate in a later operation. -/// The mcp-server variant of . + +/// Where and when the runtime observed the trust metadata. Observation time is not the authority's evaluation time and must not be used to infer staleness. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateMcpServer : CatalogCandidate +public sealed class CatalogTrustProvenance { - /// - [JsonIgnore] - public override string Kind => "mcp-server"; - - /// Description taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Display name taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } - - /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. + /// ISO 8601 timestamp with a timezone offset at which the runtime observed the search result carrying this trust field. [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("handle")] - public required string Handle { get; set; } + [MinLength(20)] + [MaxLength(64)] + [JsonPropertyName("observedAt")] + public DateTimeOffset ObservedAt { get; set; } - /// ISO 8601 timestamp after which the handle is stale and will be rejected. - [JsonPropertyName("handleExpiresAt")] - public required string HandleExpiresAt { get; set; } + /// Bounded authority that supplied the trust field. + [JsonPropertyName("source")] + public CatalogTrustSource Source { get; set; } +} - /// Whether this MCP server can be planned for installation, and if policy prevents it. - [JsonPropertyName("installability")] - public required CatalogMcpServerInstallability Installability { get; set; } +/// A recognised current Agent Finder T1 or T2 trust tier. +/// The current variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class CatalogTrustSnapshotCurrent : CatalogTrustSnapshot +{ + /// + [JsonIgnore] + public override string Status => "current"; - /// JSON MCP media type of the underlying card. - [JsonPropertyName("mediaType")] - public required McpServerCardMediaType MediaType { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Where the catalog reference was observed, without the card itself or any content digest. + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. [JsonPropertyName("provenance")] - public required CatalogMcpServerCandidateProvenance Provenance { get; set; } - - /// Publisher taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("publisher")] - public string? Publisher { get; set; } + public required CatalogTrustProvenance Provenance { get; set; } - /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. - [JsonPropertyName("source")] - public required CatalogCandidateSource Source { get; set; } + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } - /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("trust")] - public CatalogTrustSnapshot? Trust { get; set; } + /// Service-computed T1 or T2 trust tier. + [JsonPropertyName("tier")] + public required CatalogTrustTier Tier { get; set; } } -/// Where and when an AI skill catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. +/// Discriminator: the authority omitted trust metadata. +/// The absent variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogAiSkillCandidateProvenance +public partial class CatalogTrustSnapshotAbsent : CatalogTrustSnapshot { - /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. - [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("authority")] - public string Authority { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Status => "absent"; - /// Media type advertised for the referenced AI skill card. - [JsonPropertyName("mediaType")] - public CatalogAiSkillMediaType MediaType { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. - [JsonPropertyName("observedAt")] - public string ObservedAt { get; set; } = string.Empty; + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// An inert AI skill catalog result. Verified Skill candidates may be installable only when the runtime reports installability and the selected session is permitted to plan installation. -/// The ai-skill variant of . +/// Discriminator: the authority explicitly marked the assessment stale. +/// The stale variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateAiSkill : CatalogCandidate +public partial class CatalogTrustSnapshotStale : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "ai-skill"; + public override string Status => "stale"; - /// Description taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Display name taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. - [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("handle")] - public required string Handle { get; set; } + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } - /// ISO 8601 timestamp after which the handle is stale and will be rejected. - [JsonPropertyName("handleExpiresAt")] - public required string HandleExpiresAt { get; set; } + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } +} - /// Whether this AI skill candidate can be planned for verified installation in the selected session. - [JsonPropertyName("installability")] - public required CatalogAiSkillInstallability Installability { get; set; } +/// Discriminator: the authority explicitly reported a downgraded assessment. +/// The downgraded variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class CatalogTrustSnapshotDowngraded : CatalogTrustSnapshot +{ + /// + [JsonIgnore] + public override string Status => "downgraded"; - /// Media type of the underlying AI skill card. - [JsonPropertyName("mediaType")] - public required CatalogAiSkillMediaType MediaType { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Where the catalog reference was observed, without the card itself or any content digest. + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. [JsonPropertyName("provenance")] - public required CatalogAiSkillCandidateProvenance Provenance { get; set; } - - /// Publisher taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("publisher")] - public string? Publisher { get; set; } - - /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. - [JsonPropertyName("source")] - public required CatalogCandidateSource Source { get; set; } + public required CatalogTrustProvenance Provenance { get; set; } - /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("trust")] - public CatalogTrustSnapshot? Trust { get; set; } + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// Where and when an Agent Plugin catalog reference was observed. Discovery provenance deliberately carries no descriptor URL, raw data, candidate handle, or content digest. +/// Discriminator: the authority explicitly revoked the assessment. +/// The revoked variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogAgentPluginCandidateProvenance +public partial class CatalogTrustSnapshotRevoked : CatalogTrustSnapshot { - /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. - [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("authority")] - public string Authority { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Status => "revoked"; - /// Canonical Agent Plugin media type. - [JsonPropertyName("mediaType")] - public CatalogAgentPluginMediaType MediaType { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. - [JsonPropertyName("observedAt")] - public string ObservedAt { get; set; } = string.Empty; + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// Syntactically validated GitHub repository provenance declared by catalog metadata. This is a source claim rather than proof that the descriptor URL resolves to the repository. +/// Discriminator: the authority supplied a bounded trust value this runtime does not understand. +/// The unsupported variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogPluginRepositorySource +public partial class CatalogTrustSnapshotUnsupported : CatalogTrustSnapshot { - /// Case-preserving safe relative POSIX path derived from metadata.repoPath. - [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)] - [MaxLength(256)] - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Status => "unsupported"; - /// Canonical lowercase owner/repository name derived from metadata.sourceSet. - [RegularExpression("^[a-z0-9_.-]+/[a-z0-9_.-]+$")] - [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(3)] - [MaxLength(256)] - [JsonPropertyName("repository")] - public string Repository { get; set; } = string.Empty; + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } + + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// An inert Agent Plugin catalog result. Its canonical catalog identity, declared version, repository source claim, and explicit compatibility tags are safe to correlate, while its descriptor, URL, raw data, and installed-plugin state remain runtime-private. This contract-only variant does not mint or expose a candidate handle. -/// The plugin variant of . +/// Discriminator: the trust field was empty, unbounded, or had the wrong JSON type. +/// The malformed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidatePlugin : CatalogCandidate +public partial class CatalogTrustSnapshotMalformed : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "plugin"; + public override string Status => "malformed"; - /// Explicit validated compatibility tags, in canonical order. An empty list means the source declared no recognised compatibility; clients must not infer compatibility from other fields. `canvas-only` requires both `canvas` and `github-copilot`. - [JsonPropertyName("compatibilityTags")] - public required IList CompatibilityTags { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Description taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } +} + +/// Catalogue identity retained from a bound candidate or plan at installation time. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class InstallationCatalogueIdentity +{ + /// Catalogue description retained at install planning time. [JsonPropertyName("description")] public string? Description { get; set; } - /// Display name taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] + /// Human display name retained from the catalogue candidate. [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } - - /// Validated, normalised catalogue resource URN. This identity comes only from the catalog identifier and is never inferred from display text or installed-plugin state. - [JsonPropertyName("identity")] - public required string Identity { get; set; } - - /// Canonical Agent Plugin media type. - [JsonPropertyName("mediaType")] - public required CatalogAgentPluginMediaType MediaType { get; set; } + public string DisplayName { get; set; } = string.Empty; - /// Where the Agent Plugin catalog reference was observed, without its descriptor, URL, raw data, or content digest. - [JsonPropertyName("provenance")] - public required CatalogAgentPluginCandidateProvenance Provenance { get; set; } + /// Catalogue item URL when supplied by the authority. + [JsonPropertyName("itemUrl")] + public string? ItemUrl { get; set; } - /// Publisher taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + /// Catalogue publisher retained at install planning time. [JsonPropertyName("publisher")] public string? Publisher { get; set; } - /// Bounded repository provenance declared through the catalog's sourceSet and repoPath metadata. It contains no descriptor URL. + /// Authority resource identifier when supplied by the catalogue. + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } + + /// Catalogue authority/source string that supplied the candidate. [JsonPropertyName("source")] - public required CatalogPluginRepositorySource Source { get; set; } + public string Source { get; set; } = string.Empty; - /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility and emitted only when the caller also requires the trust-snapshot capability. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("trust")] - public CatalogTrustSnapshot? Trust { get; set; } + /// Catalogue trust observation retained at install planning time. + [JsonPropertyName("trustAtInstall")] + public CatalogTrustSnapshot? TrustAtInstall { get; set; } - /// Optional version declared by the catalog source. Omitted rather than guessed when the source supplies no version. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + /// Catalogue version retained at install planning time. [JsonPropertyName("version")] public string? Version { get; set; } } -/// Authority-reported navigation metadata, returned only to callers requiring catalog-search-pagination and only when a supported token is present. Tokenless first-page and continuation responses omit this object; no counts are inferred from candidates. The opaque token may be retained for previous or numbered navigation even when hasNextPage is false. +/// Durable configuration ownership is distinct from session-specific usability. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogSearchPagination +public sealed class McpInstallationSummary { - /// One-based page returned by the authority. - [JsonPropertyName("currentPage")] - public int CurrentPage { get; set; } - - /// Whether the authority token advertises a valid next target within the navigation window. Not inferred from token presence, truncated, or currentPage being less than pageCount. - [JsonPropertyName("hasNextPage")] - public bool HasNextPage { get; set; } + /// Catalogue identity retained from the installed plan when available. + [JsonPropertyName("catalogue")] + public InstallationCatalogueIdentity? Catalogue { get; set; } - /// Navigation window ceiling ceil(1000 / pageSize), not the number of existing pages. Legal targets must not exceed this ceiling or the token's signed pageCount. - [JsonPropertyName("maxPage")] - public int MaxPage { get; set; } + /// Exact alternative retained in the installing receipt. + [JsonPropertyName("choiceId")] + public string ChoiceId { get; set; } = string.Empty; - /// Backend-reported page count, which may exceed maxPage. Present pagination metadata always describes a multi-page result; zero- and single-page responses omit pagination. Navigation targets must also be within the signed pageCount carried by the supplied token. - [JsonPropertyName("pageCount")] - public long PageCount { get; set; } + /// Identity retained from the validated original plan. + [JsonPropertyName("identity")] + public McpPlanResourceIdentity Identity { get => field ??= new(); set; } - /// Page size bound to the search, equal to the effective request limit. - [JsonPropertyName("pageSize")] - public int PageSize { get; set; } + /// Exact durable installation receipt identity. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; - /// Opaque pagination token. Session-bound search returns an expiring runtime-owned reference retaining the exact private authority token, original search and authority. Legacy unbound search returns the authority token unchanged, without a runtime-created expiry. Only the runtime unwraps tokens or changes targetPage; SDK consumers must not decode, modify or log them. - [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)] - [MaxLength(4096)] - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// ISO 8601 wall-clock installation time when available. + [JsonPropertyName("installedAt")] + public string? InstalledAt { get; set; } - /// Backend-reported count for this response, not the number of returned candidates. Its relationship to the full query result set is unknown. - [JsonPropertyName("totalCount")] - public long TotalCount { get; set; } + /// Original installing operation, not a fresh management operation. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// The relationship of totalCount to the complete query result set is unknown; neither exactness nor a lower-bound guarantee is implied. - [JsonPropertyName("totalCountRelation")] - public CatalogSearchTotalCountRelation TotalCountRelation { get; set; } + /// Ownership or setup state, never inferred proof of tool usability. + [JsonPropertyName("state")] + public McpInstallationState State { get; set; } } -/// A completed catalog search containing inert candidate summaries. MCP server and AI skill variants carry a single-use handle; the Agent Plugin variant is handleless. -/// The succeeded variant of . +/// The listed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultSucceeded : CatalogSearchResult +public partial class McpInstallationManagementOutcomeListed : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Kind => "succeeded"; - - /// Matching candidates, never more than the requested limit. All text is inert untrusted data. - [JsonPropertyName("candidates")] - public required IList Candidates { get; set; } - - /// Protocol version and capabilities the runtime honoured. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } - - /// Navigation metadata for callers explicitly requiring catalog-search-pagination. Omitted when the authority returns no token, including tokenless first-page and continuation responses. Counts are never substituted from candidates.length. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pagination")] - public CatalogSearchPagination? Pagination { get; set; } - - /// Pseudonymous identifier for this search, issued by the runtime or by the catalog authority it queried and never by the caller, so it cannot be forged or replayed to attribute an install to a search that never happened. Always present on a success, so a result set can be tied to the installs it leads to. It identifies a search rather than a person: it is derived from no user, account, device, or query data, and must never be joined with user identity to re-identify anyone. - [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)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + public override string Kind => "listed"; - /// Legacy indication that the authority returned a page token. Preserved for compatibility; this is not a has-next-page indicator. Use pagination.hasNextPage when pagination metadata is present. - [JsonPropertyName("truncated")] - public required bool Truncated { get; set; } + /// Owned receipts visible to the selected account and host. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// The recovered variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultNegotiationRefused : CatalogSearchResult +public partial class McpInstallationManagementOutcomeRecovered : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Kind => "negotiation-refused"; + public override string Kind => "recovered"; - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Freshly inspected receipts after successful durable reconciliation. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } +} - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } +/// Exact inert removal plan. No configuration or credentials have changed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpUninstallPlan +{ + /// Original wall-clock expiry in milliseconds. Applying never renews it. + [JsonPropertyName("expiresAtEpochMs")] + public long ExpiresAtEpochMs { get; set; } - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + /// Original owned receipt being removed. + [JsonPropertyName("installation")] + public McpInstallationSummary Installation { get => field ??= new(); set; } - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// The original operation, inspectable and cancellable on this same connection. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Exact configured input slots owned by this installation, never shared OAuth tokens. + [JsonPropertyName("ownedSecretCount")] + public long OwnedSecretCount { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// One-use original connection and authority-bound plan handle. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// Shared authentication is deliberately retained; revocation is a separate action. + [JsonPropertyName("preservesSharedAuthentication")] + public bool PreservesSharedAuthentication { get; set; } + + /// Whether removal restores a protected earlier configuration. + [JsonPropertyName("restoresPreviousConfiguration")] + public bool RestoresPreviousConfiguration { get; set; } } -/// The request asked for a candidate kind this runtime does not serve. -/// The unsupported-kind variant of . +/// The uninstall-planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultUnsupportedKind : CatalogSearchResult +public partial class McpInstallationManagementOutcomeUninstallPlanned : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Kind => "unsupported-kind"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// The kinds from the request that are not supported. - [JsonPropertyName("requestedKinds")] - public required IList RequestedKinds { get; set; } + public override string Kind => "uninstall-planned"; - /// Every candidate kind this runtime can serve. - [JsonPropertyName("supportedKinds")] - public required IList SupportedKinds { get; set; } + /// Original owned removal plan and operation. + [JsonPropertyName("plan")] + public required McpUninstallPlan Plan { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Status snapshot from the original connection, independent of new-work account availability. +/// Polymorphic base type discriminated by phase. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultInvalidRequest : CatalogSearchResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "phase", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationOperationStatusPreparing), "preparing")] +[JsonDerivedType(typeof(McpInstallationOperationStatusPrepared), "prepared")] +[JsonDerivedType(typeof(McpInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] +[JsonDerivedType(typeof(McpInstallationOperationStatusRevalidating), "revalidating")] +[JsonDerivedType(typeof(McpInstallationOperationStatusApplying), "applying")] +[JsonDerivedType(typeof(McpInstallationOperationStatusCompleted), "completed")] +public partial class McpInstallationOperationStatus { - /// - [JsonIgnore] - public override string Kind => "invalid-request"; - - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } - - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// The type discriminator. + [JsonPropertyName("phase")] + public virtual string Phase { get; set; } = string.Empty; } -/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. -/// The authentication-required variant of . + +/// The preparing variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultAuthenticationRequired : CatalogSearchResult +public partial class McpInstallationOperationStatusPreparing : McpInstallationOperationStatus { /// [JsonIgnore] - public override string Kind => "authentication-required"; + public override string Phase => "preparing"; - /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether cancellation has been requested, not proof that a write was undone. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. - [JsonPropertyName("reason")] - public required CatalogAuthenticationRequiredReason Reason { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Registry or enterprise policy refused the operation. -/// The policy-rejected variant of . +/// The prepared variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultPolicyRejected : CatalogSearchResult +public partial class McpInstallationOperationStatusPrepared : McpInstallationOperationStatus { /// [JsonIgnore] - public override string Kind => "policy-rejected"; + public override string Phase => "prepared"; - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether the inert prepared operation was asked to cancel. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Which authority produced the decision. - [JsonPropertyName("source")] - public required McpPlanPolicySource Source { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. -/// The network-failure variant of . +/// The awaiting-confirmation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultNetworkFailure : CatalogSearchResult +public partial class McpInstallationOperationStatusAwaitingConfirmation : McpInstallationOperationStatus { /// [JsonIgnore] - public override string Kind => "network-failure"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogNetworkFailureReason Reason { get; set; } + public override string Phase => "awaiting-confirmation"; - /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("retryAfterSeconds")] - public int? RetryAfterSeconds { get; set; } + /// Whether the pending human callback was asked to cancel. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// HTTP status code, when the failure was a rejected response. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("statusCode")] - public int? StatusCode { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. -/// The unsafe-retrieval variant of . +/// The revalidating variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultUnsafeRetrieval : CatalogSearchResult +public partial class McpInstallationOperationStatusRevalidating : McpInstallationOperationStatus { /// [JsonIgnore] - public override string Kind => "unsafe-retrieval"; + public override string Phase => "revalidating"; - /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether source or authority revalidation was asked to cancel. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogUnsafeRetrievalReason Reason { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// A card could not be parsed or did not satisfy its declared media type's schema. -/// The malformed-card variant of . +/// The applying variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultMalformedCard : CatalogSearchResult +public partial class McpInstallationOperationStatusApplying : McpInstallationOperationStatus { /// [JsonIgnore] - public override string Kind => "malformed-card"; - - /// Media type the card was interpreted as, when it declared one this runtime recognises. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mediaType")] - public CatalogMediaType? MediaType { get; set; } + public override string Phase => "applying"; - /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether applying was asked to cancel; already-started effects retain their lease. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// How the card failed validation. - [JsonPropertyName("reason")] - public required CatalogMalformedCardReason Reason { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. -/// The contract-violation variant of . +/// Terminal mutation result. Uncertainty is not approval, rollback or permission to replay. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultContractViolation : CatalogSearchResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationOutcomeInstalled), "installed")] +[JsonDerivedType(typeof(McpInstallationOutcomeUninstalled), "uninstalled")] +[JsonDerivedType(typeof(McpInstallationOutcomeRolledBack), "rolled-back")] +[JsonDerivedType(typeof(McpInstallationOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(McpInstallationOutcomeDeclined), "declined")] +[JsonDerivedType(typeof(McpInstallationOutcomeCancelled), "cancelled")] +[JsonDerivedType(typeof(McpInstallationOutcomeRefused), "refused")] +public partial class McpInstallationOutcome { - /// - [JsonIgnore] - public override string Kind => "contract-violation"; - - /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Which rule the response broke. - [JsonPropertyName("reason")] - public required CatalogContractViolationReason Reason { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. -/// The unavailable variant of . + +/// The installed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultUnavailable : CatalogSearchResult +public partial class McpInstallationOutcomeInstalled : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "unavailable"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Why the operation is unavailable. - [JsonPropertyName("reason")] - public required CatalogUnavailableReason Reason { get; set; } -} + public override string Kind => "installed"; -/// An explicit numbered-page request. SDK consumers treat the token as opaque. For bound search, the runtime unwraps an expiring owner-bound reference to the private authority token; only the runtime changes the authority token's targetPage. Legacy unbound navigation keeps its authority-issued token semantics. No snapshot stability is promised. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogSearchPage -{ - /// Requested one-based page. Must not exceed either the token's signed pageCount or the navigation window ceil(1000 / pageSize). Repeat the search without page to discover newly available pages beyond that signed pageCount. - [JsonPropertyName("number")] - public int Number { get; set; } + /// Durable installation succeeded but final transaction cleanup remains. + [JsonPropertyName("cleanupPending")] + public required bool CleanupPending { get; set; } - /// Opaque pagination token from an earlier response, owner-bound when session-bound search was requested. Never decode, modify or log it in an SDK consumer. Expired or foreign bound references require a fresh bound search, not a legacy retry. - [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)] - [MaxLength(4096)] - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// Receipt identity produced by the confirmed transaction. + [JsonPropertyName("installation")] + public required McpInstallationSummary Installation { get; set; } } -/// A bounded catalog search. Both the query length and the result count are capped by the schema so a caller cannot request an unbounded scan. +/// The uninstalled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogSearchRequest +public partial class McpInstallationOutcomeUninstalled : McpInstallationOutcome { - /// Protocol version and capabilities the caller requires. - [JsonPropertyName("contract")] - public required CatalogClientContract Contract { get; set; } + /// + [JsonIgnore] + public override string Kind => "uninstalled"; - /// Restrict results to these candidate kinds. Agent Plugins are opt-in and require the `agent-plugin-discovery` capability so protocol-v3 clients generated before that variant cannot receive an unknown result; when omitted, the backwards-compatible MCP server and AI skill kinds are searched. - [JsonPropertyName("kinds")] - public IList? Kinds { get; set; } + /// Durable removal succeeded but final cleanup remains. + [JsonPropertyName("cleanupPending")] + public required bool CleanupPending { get; set; } - /// Maximum number of candidates to return. Defaults to 10 when omitted. - [JsonPropertyName("limit")] - public int? Limit { get; set; } + /// Exact removed receipt identity. + [JsonPropertyName("installationId")] + public required string InstallationId { get; set; } - /// Numbered navigation using metadata from an earlier response. Requires catalog-search-pagination and the same query, kinds and effective limit. Omit for a fresh first-page search. - [JsonPropertyName("page")] - public CatalogSearchPage? Page { get; set; } + /// Original removal operation. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } - /// - /// Select an existing attached local session. Requires authenticated, session-bound search. - /// The runtime never creates, resumes or reconfigures a session to honour this selector. - /// - [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)] - [MaxLength(256)] - [JsonPropertyName("policySessionId")] - public string? PolicySessionId { get; set; } + /// Any grants in the incumbent shared OAuth store remain unowned and retained. + [JsonPropertyName("preservedSharedAuthentication")] + public required bool PreservedSharedAuthentication { get; set; } - /// Free-text search query. Persisted as tool input for session continuity, but omitted from telemetry. - [RegularExpression("\\S")] - [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)] - [MaxLength(256)] - [JsonPropertyName("query")] - public required string Query { get; set; } -} + /// Exact owned input slots removed, excluding shared OAuth credentials. + [JsonPropertyName("removedOwnedSecrets")] + public required long RemovedOwnedSecrets { get; set; } -/// Typed outcome of catalog.select. Only the selected host result carries a fresh candidate handle; the model-facing projection removes both that handle and searchId. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogSelectionResultSelected), "selected")] -[JsonDerivedType(typeof(CatalogSelectionResultDeclined), "declined")] -[JsonDerivedType(typeof(CatalogSelectionResultCancelled), "cancelled")] -[JsonDerivedType(typeof(CatalogSelectionResultTimedOut), "timed-out")] -[JsonDerivedType(typeof(CatalogSelectionResultInvalid), "invalid")] -[JsonDerivedType(typeof(CatalogSelectionResultStale), "stale")] -[JsonDerivedType(typeof(CatalogSelectionResultReplayed), "replayed")] -[JsonDerivedType(typeof(CatalogSelectionResultForeign), "foreign")] -[JsonDerivedType(typeof(CatalogSelectionResultWrongKind), "wrong-kind")] -[JsonDerivedType(typeof(CatalogSelectionResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(CatalogSelectionResultInvalidRequest), "invalid-request")] -[JsonDerivedType(typeof(CatalogSelectionResultUnavailable), "unavailable")] -public partial class CatalogSelectionResult -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Whether protected pre-install configuration was restored. + [JsonPropertyName("restoredPreviousConfiguration")] + public required bool RestoredPreviousConfiguration { get; set; } } - -/// The chosen candidate was transferred into a fresh bounded single-use handle for a later explicit planning request. -/// The selected variant of . +/// The durable transaction was aborted or fully compensated. +/// The rolled-back variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultSelected : CatalogSelectionResult +public partial class McpInstallationOutcomeRolledBack : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "selected"; + public override string Kind => "rolled-back"; - /// Fresh single-use candidate handle accepted by mcp.planInstall. Returned only to the native host and never included in model-tool output. - [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)] - [MaxLength(256)] - [JsonPropertyName("candidateHandle")] - public required string CandidateHandle { get; set; } + /// Original connection-owned operation. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } - /// The exact search identifier privately bound to the selected candidate. - [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)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Cause of the fully aborted or compensated operation. + [JsonPropertyName("reason")] + public required McpInstallationFailureReason Reason { get; set; } } -/// The caller explicitly declined every candidate and the retained search state was released. -/// The declined variant of . +/// A write may have completed. Recover and inspect durable state before retrying. +/// The recovery-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultDeclined : CatalogSelectionResult +public partial class McpInstallationOutcomeRecoveryRequired : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "declined"; + public override string Kind => "recovery-required"; - /// The search identifier privately bound to the released selection group. - [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)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Operation whose durable result must be recovered and inspected. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// The caller cancelled the selection interaction and the retained search state was released. -/// The cancelled variant of . +/// The declined variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultCancelled : CatalogSelectionResult +public partial class McpInstallationOutcomeDeclined : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "cancelled"; + public override string Kind => "declined"; - /// The search identifier privately bound to the released selection group. - [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)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Original operation explicitly declined by the user. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// The host declared that its live selection interaction timed out, and the retained search state was released. -/// The timed-out variant of . +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultTimedOut : CatalogSelectionResult +public partial class McpInstallationOutcomeCancelled : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "timed-out"; + public override string Kind => "cancelled"; - /// The search identifier privately bound to the released selection group. - [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)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Original operation cancelled before a terminal application result. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// The selection reference was malformed or unknown. -/// The invalid variant of . +/// The refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultInvalid : CatalogSelectionResult +public partial class McpInstallationOutcomeRefused : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "invalid"; + public override string Kind => "refused"; - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Present once an operation has been allocated; never a plan handle. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("operationId")] + public string? OperationId { get; set; } + + /// Specific bounded refusal, never a success-shaped fallback. + [JsonPropertyName("reason")] + public required McpInstallationFailureReason Reason { get; set; } } -/// The runtime-enforced selection reference lifetime elapsed before the request arrived. -/// The stale variant of . +/// The completed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultStale : CatalogSelectionResult +public partial class McpInstallationOperationStatusCompleted : McpInstallationOperationStatus { /// [JsonIgnore] - public override string Kind => "stale"; + public override string Phase => "completed"; - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether cancellation was requested before the terminal result. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } + + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } + + /// Immutable terminal receipt. + [JsonPropertyName("outcome")] + public required McpInstallationOutcome Outcome { get; set; } } -/// The selection group was already terminated or its pending host hand-off was already claimed. -/// The replayed variant of . +/// The operation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultReplayed : CatalogSelectionResult +public partial class McpInstallationManagementOutcomeOperation : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Kind => "replayed"; + public override string Kind => "operation"; - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Original-connection operation snapshot. + [JsonPropertyName("operation")] + public required McpInstallationOperationStatus Operation { get; set; } } -/// The selection reference belongs to another runtime instance or session. -/// The foreign variant of . +/// The refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultForeign : CatalogSelectionResult +public partial class McpInstallationManagementOutcomeRefused : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Kind => "foreign"; + public override string Kind => "refused"; - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Specific bounded refusal. + [JsonPropertyName("reason")] + public required McpInstallationFailureReason Reason { get; set; } } -/// The presented opaque handle was issued for another catalog operation. -/// The wrong-kind variant of . +/// The outcome variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultWrongKind : CatalogSelectionResult +public partial class McpInstallationManagementResultOutcome : McpInstallationManagementResult { /// [JsonIgnore] - public override string Kind => "wrong-kind"; + public override string Kind => "outcome"; - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Capabilities actually honoured for this request. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } + + /// Observed management outcome. + [JsonPropertyName("outcome")] + public required McpInstallationManagementOutcome Outcome { get; set; } } /// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultNegotiationRefused : CatalogSelectionResult +public partial class McpInstallationManagementResultNegotiationRefused : McpInstallationManagementResult { /// [JsonIgnore] @@ -6197,9 +6133,9 @@ public partial class CatalogSelectionResultNegotiationRefused : CatalogSelection } /// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultInvalidRequest : CatalogSelectionResult +public partial class McpInstallationManagementResultInvalidRequest : McpInstallationManagementResult { /// [JsonIgnore] @@ -6216,542 +6152,458 @@ public partial class CatalogSelectionResultInvalidRequest : CatalogSelectionResu public required string Message { get; set; } } -/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. -/// The unavailable variant of . +/// One Registry string-valued configuration entry for the selected transport. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultUnavailable : CatalogSelectionResult +public sealed class McpInstallationInput { - /// - [JsonIgnore] - public override string Kind => "unavailable"; + /// Exact category declared by the selected choice. + [JsonPropertyName("category")] + public McpPlanValueCategory Category { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Exact key declared by the selected choice. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Why the operation is unavailable. - [JsonPropertyName("reason")] - public required CatalogUnavailableReason Reason { get; set; } + /// Explicit non-secret value. Secret placeholders use a separate input channel. + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; } -/// Terminates one retained catalog selection group through an opaque reference previously returned by the model-safe search projection. +/// A request-local value for one exact reviewed placeholder. Never logged or persisted in a plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CatalogSelectionRequest +public sealed class McpInstallationSecret { - /// Protocol version and capabilities the caller requires. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } - - /// The terminal outcome declared by the caller. Timed-out means the host's live interaction deadline elapsed; a reference whose runtime TTL elapsed is rejected separately as stale. - [JsonPropertyName("outcome")] - public CatalogSelectionDecision Outcome { get; set; } - - /// Opaque runtime-instance scoped reference to one visible candidate. For a non-selected outcome, any candidate reference from the same search closes that search's retained group. - [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)] - [MaxLength(256)] - [JsonPropertyName("selectionRef")] - public string SelectionRef { get; set; } = string.Empty; + /// Exact placeholder from the selected choice, not a caller-chosen backend identifier. + [JsonPropertyName("placeholder")] + public string Placeholder { get; set; } = string.Empty; - /// Locally owned root session whose retained search state is being resolved. - [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)] - [MaxLength(256)] - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Fresh explicit secret value. It is omitted from confirmation reviews and telemetry. + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; } -/// Information about an installed plugin tracked in global state. +/// Side-effect-free preparation of one original bound remote MCP choice. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstalledPluginInfo +internal sealed class McpPrepareInstallRequest { - /// Opaque, stable hash identifying a direct (non-marketplace) install source. Present only for direct repo / URL / local installs; absent for marketplace plugins. Same source yields the same id; distinct sources never collide. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } - - /// Whether the plugin is currently enabled for new sessions. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Exact selected alternative from that plan. + [JsonPropertyName("choiceId")] + public string ChoiceId { get; set; } = string.Empty; - /// Whether the managed desired plugin currently has an installed or live record. Set to false for a managed desired entry retained in the listing after installation or reconciliation failed. - [JsonPropertyName("installed")] - public bool? Installed { get; set; } + /// Required bound catalogue and confirmed remote installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — a plugin belonging to a directory/local marketplace, which is loaded from its real directory on every pass instead of a copy under the installed-plugins cache. Its presence is what marks a listed plugin as live: such a plugin is always present on disk, so `enabled` is its only meaningful state and it is never "not installed". - [JsonPropertyName("installedFrom")] - public string? InstalledFrom { get; set; } + /// + /// Declared non-secret values. Non-empty only when the caller requires + /// `mcp-configured-remote-installation`; omitted values use the card default. + /// + [JsonPropertyName("inputs")] + public IList Inputs { get => field ??= []; set; } - /// Whether enterprise managed settings control this plugin's enabled state. - [JsonPropertyName("managed")] - public bool? Managed { get; set; } + /// Original single-use bound plan, never a client-authored configuration. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// The enabled state required by enterprise managed settings, when this plugin spec is managed. - [JsonPropertyName("managedDesiredEnabled")] - public bool? ManagedDesiredEnabled { get; set; } + /// An existing local session attached to this connection, not permission to attach one. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; - /// Marketplace the plugin came from. Empty string ("") for direct repo / URL / local installs. - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; + /// + /// One entry per declared secret placeholder of the selected choice. Non-empty + /// only when the caller requires `mcp-configured-remote-installation`. + /// + [JsonPropertyName("secrets")] + public IList Secrets { get => field ??= []; set; } - /// Plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The trusted host presents this choice alongside the exact secret placeholders. + [JsonPropertyName("secretStorage")] + public McpInstallationSecretStorage SecretStorage { get; set; } - /// Runtime-reported plugin provenance. Currently set to "builtin" only for plugins registered through the trusted host built-in boundary; absent for installed, marketplace, direct, and live plugins. + /// The exact original source, used transiently only after confirmation. [JsonPropertyName("source")] - public string? Source { get; set; } - - /// Installed version (when reported by the plugin manifest). - [JsonPropertyName("version")] - public string? Version { get; set; } + public McpServerCardReference Source { get => field ??= new(); set; } } -/// Plugins installed in user/global state. +/// An installation result together with the exact honoured contract, or a negotiation refusal. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginListResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationResultOutcome), "outcome")] +[JsonDerivedType(typeof(McpInstallationResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(McpInstallationResultInvalidRequest), "invalid-request")] +public partial class McpInstallationResult { - /// Installed plugins. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Result of installing a plugin. + +/// The outcome variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginInstallResult +public partial class McpInstallationResultOutcome : McpInstallationResult { - /// Set when the install path is deprecated (e.g. direct repo / URL / local installs). Callers should surface this to end users. - [JsonPropertyName("deprecationWarning")] - public string? DeprecationWarning { get; set; } - - /// The newly installed plugin's metadata. - [JsonPropertyName("plugin")] - public InstalledPluginInfo Plugin { get => field ??= new(); set; } - - /// Optional post-install message provided by the plugin (e.g. setup instructions). - [JsonPropertyName("postInstallMessage")] - public string? PostInstallMessage { get; set; } + /// + [JsonIgnore] + public override string Kind => "outcome"; - /// Number of skills discovered and installed from the plugin. - [JsonPropertyName("skillsInstalled")] - public long SkillsInstalled { get; set; } + /// Capabilities actually honoured for this request. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// Where the completed plugin tree was staged before atomic promotion. - [JsonPropertyName("stagingMode")] - public PluginInstallStagingMode? StagingMode { get; set; } + /// Terminal result of the original operation. + [JsonPropertyName("outcome")] + public required McpInstallationOutcome Outcome { get; set; } } -/// Plugin source and optional working directory for relative-path resolution. +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsInstallRequest +public partial class McpInstallationResultNegotiationRefused : McpInstallationResult { - /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; - - /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } -} + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; -/// Name (or spec) of the plugin to uninstall. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUninstallRequest -{ - /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; -} + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } -/// Result of updating a single plugin. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginUpdateResult -{ - /// Version after the update, when reported by the plugin manifest. - [JsonPropertyName("newVersion")] - public string? NewVersion { get; set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// Version that was previously installed, when available. - [JsonPropertyName("previousVersion")] - public string? PreviousVersion { get; set; } + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } - /// Number of skills discovered and installed after the update. - [JsonPropertyName("skillsInstalled")] - public long SkillsInstalled { get; set; } -} + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } -/// Name (or spec) of the plugin to update. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUpdateRequest -{ - /// Plugin name or "plugin@marketplace" spec to update. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// Per-plugin result from updating all plugins, with versions, skills installed, success flag, and optional error. +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginUpdateAllEntry +public partial class McpInstallationResultInvalidRequest : McpInstallationResult { - /// Error message (failure only). - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Marketplace the plugin came from. Empty string ("") for direct installs. - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; - - /// Plugin name that was updated. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Version after the update, when available. - [JsonPropertyName("newVersion")] - public string? NewVersion { get; set; } - - /// Previously installed version, when available. - [JsonPropertyName("previousVersion")] - public string? PreviousVersion { get; set; } + /// + [JsonIgnore] + public override string Kind => "invalid-request"; - /// Number of skills installed after the update (success only). - [JsonPropertyName("skillsInstalled")] - public long? SkillsInstalled { get; set; } + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } - /// Whether the update succeeded for this plugin. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Result of updating all installed plugins. +/// Applies exactly one previously prepared operation on its original connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginUpdateAllResult +internal sealed class McpApplyInstallRequest { - /// Per-plugin update results in deterministic order. - [JsonPropertyName("results")] - public IList Results { get => field ??= []; set; } + /// Capabilities required by the original prepared operation. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } + + /// Runtime-issued ID already returned by prepareInstall, never reused or rebound. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; + + /// Same existing attached or privately borrowed session as preparation. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. +/// Read-only preparation of one owned removal under fresh selected-session authority. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsEnableRequest +internal sealed class McpPlanUninstallRequest { - /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Required authenticated bound installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// Exact receipt to inspect, not a server-name guess. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; + + /// Existing selected session on the original connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. +/// One-use application of the exact retained removal plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsDisableRequest +internal sealed class McpApplyUninstallRequest { - /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Required authenticated bound installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// Opaque original removal plan, consumed once. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// Same existing selected session as removal preparation. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Trusted built-in plugin directories to use for this runtime process. +/// User-configured MCP servers, keyed by server name. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsBuiltinSetRequest +public sealed class McpConfigList { - /// Complete replacement set of trusted built-in plugin directories. Every entry must be an absolute local filesystem path no longer than 4096 characters. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// All MCP servers from user config, keyed by name. + [JsonPropertyName("servers")] + public IDictionary Servers { get => field ??= new Dictionary(); set; } } -/// Registered marketplace summary. +/// MCP server name and configuration to add to user configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceInfo +internal sealed class McpConfigAddRequest { - /// Whether the managed marketplace currently resolved into the runtime marketplace registry. Set to false when the desired managed entry is retained for governance visibility after loading or reconciliation failed. - [JsonPropertyName("available")] - public bool? Available { get; set; } - - /// True when this is a default marketplace shipped with the runtime. Defaults are not removable. - [JsonPropertyName("isDefault")] - public bool? IsDefault { get; set; } - - /// Whether enterprise managed settings provide and control this marketplace entry. - [JsonPropertyName("managed")] - public bool? Managed { get; set; } + /// MCP server configuration (stdio process or remote HTTP/SSE). + [JsonPropertyName("config")] + public JsonElement Config { get; set; } - /// Marketplace name (matches the @marketplace suffix in plugin specs). + /// Unique name for the MCP server. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("name")] public string Name { get; set; } = string.Empty; - - /// Human-readable description of where the marketplace data is fetched from (e.g. "GitHub: owner/repo"). - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; } -/// All registered marketplaces, including built-in defaults. +/// MCP server name and replacement configuration to write to user configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceListResult +internal sealed class McpConfigUpdateRequest { - /// Registered marketplaces. - [JsonPropertyName("marketplaces")] - public IList Marketplaces { get => field ??= []; set; } + /// MCP server configuration (stdio process or remote HTTP/SSE). + [JsonPropertyName("config")] + public JsonElement Config { get; set; } + + /// Name of the MCP server to update. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("name")] + public string Name { get; set; } = string.Empty; } -/// Result of registering a new marketplace. +/// MCP server name to remove from user configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceAddResult +internal sealed class McpConfigRemoveRequest { - /// Final name of the marketplace as resolved from its manifest. + /// OAuth Client ID Metadata Document URL whose persisted credentials should also be removed. + [JsonPropertyName("authClientIdMetadataUrl")] + public string? AuthClientIdMetadataUrl { get; set; } + + /// Name of the MCP server to remove. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("name")] public string Name { get; set; } = string.Empty; } -/// Marketplace source and optional working directory for relative-path resolution. +/// MCP server names to enable for new sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesAddRequest +internal sealed class McpConfigEnableRequest { - /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; - - /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// 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. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } } -/// Outcome of the remove attempt, including dependent-plugin info when applicable. +/// MCP server names to disable for new sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceRemoveResult +internal sealed class McpConfigDisableRequest { - /// Names of installed plugins that prevented removal. Populated only when `removed=false`. - [JsonPropertyName("dependentPlugins")] - public IList? DependentPlugins { get; set; } - - /// True when the marketplace was actually removed. False when removal was skipped because the marketplace has dependent plugins and `force` was not set. - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// 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. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } } -/// Name of the marketplace to remove and an optional force flag. +/// Request id naming a cancellable registry search. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesRemoveRequest +internal sealed class McpRegistryRequestIdResult { - /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } +} - /// Marketplace name to remove. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// Servers selected from the registry response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistrySearchResult +{ + /// The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. + [JsonPropertyName("servers")] + public JsonElement Servers { get; set; } } -/// Plugin entry advertised by a marketplace. +/// Registry search terms, the credential to search under, and the request id that makes the search cancellable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplacePluginInfo +internal sealed class McpRegistrySearchRequest { - /// Short description from the marketplace catalog, when present. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. + [JsonPropertyName("authInfo")] + public JsonElement AuthInfo { get; set; } - /// Plugin name as listed in the marketplace catalog. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Maximum number of servers to return. + [JsonPropertyName("limit")] + public long Limit { get; set; } + + /// Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. + [JsonPropertyName("query")] + public string? Query { get; set; } + + /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. + [JsonPropertyName("repository")] + public string? Repository { get; set; } + + /// Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// Plugins advertised by the marketplace. +/// Whether the cancel reached a live search. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceBrowseResult +internal sealed class McpRegistryCancelResult { - /// Plugins advertised by the marketplace. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } + /// True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. + [JsonPropertyName("canceled")] + public bool Canceled { get; set; } } -/// Name of the marketplace whose plugin catalog to fetch. +/// Registry search to abandon. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesBrowseRequest +internal sealed class McpRegistryCancelRequest { - /// Marketplace name to browse. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Request ID from `mcp.registry.allocateRequestId` that the search uses. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// Per-marketplace refresh result, including marketplace name, success flag, and optional failure error. +/// New-work inventory or recovery request under an explicitly selected existing session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceRefreshEntry +internal sealed class McpInstallationsRequest { - /// Error message (failure only). - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Marketplace name that was refreshed. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Whether the refresh succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Existing selected local session on this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Result of refreshing one or more marketplace catalogs. +/// Existing-operation control. A new session selector is deliberately not accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceRefreshResult +internal sealed class McpInstallationOperationRequest { - /// Per-marketplace refresh results in deterministic order. - [JsonPropertyName("results")] - public IList Results { get => field ??= []; set; } + /// Original installation wire capability; new-work authentication is not reacquired. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } + + /// Exact runtime-issued operation ID on the original connection. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; } -/// RPC data type for PluginsMarketplacesRefresh operations. +/// Installed plugin that contributes a discovered extension. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesRefreshRequest +public sealed class DiscoveredExtensionPlugin { - /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + /// Installed plugin name. [JsonPropertyName("name")] - public string? Name { get; set; } + public string Name { get; set; } = string.Empty; } -/// Agent metadata, including identifiers, display details, source, tools, model, models, reasoning effort, MCP servers, skills, and file path. +/// Discovered extension metadata and persistent enablement state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentInfo +public sealed class DiscoveredExtension { - /// Description of the agent's purpose. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Whether model-driven invocation is disabled for this agent. - [JsonPropertyName("disableModelInvocation")] - public bool? DisableModelInvocation { get; set; } - - /// Human-readable display name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// Whether this extension's persistent per-ID preference is enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. + /// Source-qualified ID accepted by both server and session extension enablement methods. [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; - /// MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("mcpServers")] - public IDictionary? McpServers { get; set; } - - /// Authored preferred model id for this agent. Runtime model selection may choose a different model; omitted means no authored preference. - [JsonPropertyName("model")] - public string? Model { get; set; } - - /// Whether authored models are preferences or required constraints. - [JsonPropertyName("modelPolicy")] - public AgentModelPolicy? ModelPolicy { get; set; } - - /// Authored preferred model ids for this agent, in priority order. Runtime model selection chooses the first available model; omitted means no authored preference. - [JsonPropertyName("models")] - public IList? Models { get; set; } - - /// Name of the agent. Use `id` as the stable selection identifier. + /// Human-readable extension name. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Absolute local file path of the agent definition. Only set for file-based agents loaded from disk; remote agents do not have a path. + /// Absolute path to the extension entry module, suitable for revealing it in a file manager. [JsonPropertyName("path")] - public string? Path { get; set; } - - /// Authored base prompt for the agent. Runtime prompt assembly may add dynamic context at invocation time. Omitted from `session.agent.list` unless `includePrompt` is true. - [JsonPropertyName("prompt")] - public string? Prompt { get; set; } - - /// Authored reasoning effort for this agent. Applied on selection to models that support it; omitted means no authored preference. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + public string Path { get; set; } = string.Empty; - /// Skill names preloaded into this agent's context. Omitted means none. - [JsonPropertyName("skills")] - public IList? Skills { get; set; } + /// Containing plugin metadata for plugin-contributed extensions. + [JsonPropertyName("plugin")] + public DiscoveredExtensionPlugin? Plugin { get; set; } - /// Where the agent definition was loaded from. + /// Discovery source. [JsonPropertyName("source")] - public AgentInfoSource? Source { get; set; } - - /// Allowed tool names for this agent. Empty array means none; omitted means inherit defaults. - [JsonPropertyName("tools")] - public IList? Tools { get; set; } - - /// Whether the agent can be selected directly by the user. Agents marked `false` are subagent-only. - [JsonPropertyName("userInvocable")] - public bool? UserInvocable { get; set; } -} - -/// Agents discovered across user, project, plugin, and remote sources. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerAgentList -{ - /// All discovered agents across all sources. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } + public DiscoveredExtensionSource Source { get; set; } } -/// Optional project paths to include in agent discovery. +/// Extensions discovered from persisted Copilot home state and their effective loading mode. Launch-scoped additional plugins are not included. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsDiscoverRequest +public sealed class DiscoveredExtensions { - /// When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. - [JsonPropertyName("excludeHostAgents")] - public bool? ExcludeHostAgents { get; set; } + /// Discovered user and enabled installed-plugin extensions from persisted Copilot home state. + [JsonPropertyName("extensions")] + public IList Extensions { get => field ??= []; set; } - /// Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Effective extension loading mode. Defaults to load_and_augment when unset. + [JsonPropertyName("mode")] + public DiscoveredExtensionMode Mode { get; set; } } -/// Canonical directory where custom agents can be discovered or created, with scope, preference, and optional project path. +/// Source-qualified extension identifiers to persistently enable for future sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentDiscoveryPath +internal sealed class DiscoveredExtensionsEnableRequest { - /// Absolute path of the search/create directory (may not exist on disk yet). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Whether this is the canonical directory to create a new agent in its tier. At most one entry per tier is preferred. - [JsonPropertyName("preferredForCreation")] - public bool PreferredForCreation { get; set; } - - /// The input project path this directory was derived from (only for project scope). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } - - /// Which tier this directory belongs to. - [JsonPropertyName("scope")] - public AgentDiscoveryPathScope Scope { get; set; } + /// Source-qualified user or plugin extension IDs to enable. + [JsonPropertyName("ids")] + public IList Ids { get => field ??= []; set; } } -/// Canonical locations where custom agents can be created so the runtime will recognize them. +/// Source-qualified extension identifiers to persistently disable for future sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentDiscoveryPathList +internal sealed class DiscoveredExtensionsDisableRequest { - /// Canonical agent create/discovery directories, in priority order. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// Source-qualified user or plugin extension IDs to disable. + [JsonPropertyName("ids")] + public IList Ids { get => field ??= []; set; } } -/// Optional project paths to include when enumerating agent discovery directories. +/// The prompt the init command runs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetDiscoveryPathsRequest +internal sealed class InstructionsInitPromptResult { - /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). - [JsonPropertyName("excludeHostAgents")] - public bool? ExcludeHostAgents { get; set; } - - /// Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Prompt text authoring repository instructions. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; } /// Loaded instruction source for a session, including path, content, category, location, applicability, and optional description. @@ -6810,17 +6662,50 @@ public sealed class ServerInstructionSourceList /// Optional project paths to include in instruction discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InstructionsDiscoverRequest +public sealed class InstructionsDiscoverRequest { /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. [JsonPropertyName("excludeHostInstructions")] public bool? ExcludeHostInstructions { get; set; } + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } + /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). [JsonPropertyName("projectPaths")] public IList? ProjectPaths { get; set; } } +/// Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class InstructionsDiscoverRepoSourcesRequest +{ + /// Extra directories to scan alongside instruction directories configured in the runtime environment. + [JsonPropertyName("additionalDirs")] + public IList? AdditionalDirs { get; set; } + + /// Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } + + /// Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. + [JsonPropertyName("cwdPath")] + public string? CwdPath { get; set; } + + /// When true, also discover instruction files nested below the location. + [JsonPropertyName("enableChildInstructions")] + public bool? EnableChildInstructions { get; set; } + + /// When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. + [JsonPropertyName("isCli")] + public bool? IsCli { get; set; } + + /// Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. + [JsonPropertyName("location")] + public string Location { get; set; } = string.Empty; +} + /// Canonical file or directory where custom instructions can be discovered or created, with location, kind, preference, and project path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class InstructionDiscoveryPath @@ -6857,1807 +6742,1881 @@ public sealed class InstructionDiscoveryPathList /// Optional project paths to include when enumerating instruction discovery targets. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InstructionsGetDiscoveryPathsRequest +public sealed class InstructionsGetDiscoveryPathsRequest { /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). [JsonPropertyName("excludeHostInstructions")] public bool? ExcludeHostInstructions { get; set; } + /// Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } + /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. [JsonPropertyName("projectPaths")] public IList? ProjectPaths { get; set; } } -/// A literal choice the command input accepts, with a human-facing description. +/// Skill installation management result with the honoured contract, or a typed refusal. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandInputChoice +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationManagementResultOutcome), "outcome")] +[JsonDerivedType(typeof(SkillInstallationManagementResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(SkillInstallationManagementResultInvalidRequest), "invalid-request")] +public partial class SkillInstallationManagementResult { - /// Human-readable description shown alongside the choice. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// The literal choice value (e.g. 'on', 'off', 'show'). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Optional unstructured input hint. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandInput -{ - /// Optional literal choices the input accepts, each with a human-facing description; clients may render these as selectable options. - [JsonPropertyName("choices")] - public IList? Choices { get; set; } - - /// Optional completion hint for the input (e.g. 'directory' for filesystem path completion). - [JsonPropertyName("completion")] - public SlashCommandInputCompletion? Completion { get; set; } - /// Hint to display when command input has not been provided. - [JsonPropertyName("hint")] - public string Hint { get; set; } = string.Empty; - - /// When true, clients should pass the full text after the command name as a single argument rather than splitting on whitespace. - [JsonPropertyName("preserveMultilineInput")] - public bool? PreserveMultilineInput { get; set; } - - /// When true, the command requires non-empty input; clients should render the input hint as required. - [JsonPropertyName("required")] - public bool? Required { get; set; } -} - -/// Slash-command metadata with name, aliases, description, kind, input hint, execution allowance, and schedulability. +/// Management outcome for verified Skill inventory, planning and removal. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandInfo +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeInstallPlanned), "install-planned")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeListed), "listed")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecovered), "recovered")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRolledBack), "rolled-back")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeOperation), "operation")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeEnabledChanged), "enabled-changed")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRefused), "refused")] +public partial class SkillInstallationManagementOutcome { - /// Canonical aliases without leading slashes. - [JsonPropertyName("aliases")] - public IList? Aliases { get; set; } - - /// Whether the command may run while an agent turn is active. - [JsonPropertyName("allowDuringAgentExecution")] - public bool AllowDuringAgentExecution { get; set; } - - /// Human-readable command description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Whether the command is experimental. - [JsonPropertyName("experimental")] - public bool? Experimental { get; set; } - - /// Optional unstructured input hint. - [JsonPropertyName("input")] - public SlashCommandInput? Input { get; set; } - - /// Coarse command category for grouping and behavior: runtime built-in, skill-backed command, or SDK/client-owned command. + /// The type discriminator. [JsonPropertyName("kind")] - public SlashCommandKind Kind { get; set; } - - /// Canonical command name without a leading slash. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Whether the command may be the target of `/every` / `/after` schedules. Resolution happens at every tick, so only set this when the command is safe to re-invoke and produces an agent prompt. - [JsonPropertyName("schedulable")] - public bool? Schedulable { get; set; } -} - -/// Slash commands available in the session, after applying any include/exclude filters. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CommandList -{ - /// Commands available in this session. - [JsonPropertyName("commands")] - public IList Commands { get => field ??= []; set; } + public virtual string Kind { get; set; } = string.Empty; } -/// A single user setting's effective value alongside its default, so consumers can render settings left at their default. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingMetadata -{ - /// The centrally-known default for this setting (null when no default is registered). - [JsonPropertyName("default")] - public JsonElement Default { get; set; } - - /// True when the user has not set an explicit value for this setting (i.e. it is left at its default). Reflects whether the user has overridden the key, not whether the effective value happens to equal the default — a key explicitly set to a value identical to the default still reports false. - [JsonPropertyName("isDefault")] - public bool IsDefault { get; set; } - - /// The effective value: the user's value if set, otherwise the default. - [JsonPropertyName("value")] - public JsonElement Value { get; set; } -} -/// Per-key metadata for every known user setting (settings.json overlaid with the legacy config.json, config.json wins), including settings left at their default. Excludes repository- and enterprise-managed overrides. +/// Already-confirmed durable work must be reconciled before new mutations or inventory. +/// The recovery-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingsGetResult +public partial class SkillInstallationManagementOutcomeRecoveryRequired : SkillInstallationManagementOutcome { - /// Every known user setting keyed by setting name, each with its effective value, default, and whether it is at the default. - [JsonPropertyName("settings")] - public IDictionary Settings { get => field ??= new Dictionary(); set; } + /// + [JsonIgnore] + public override string Kind => "recovery-required"; } -/// Outcome of writing user settings. +/// Safe verified Skill review fields. No raw credential, candidate handle or plan handle. +/// Polymorphic base type discriminated by action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingsSetResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "action", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationReviewInstall), "install")] +[JsonDerivedType(typeof(SkillInstallationReviewUninstall), "uninstall")] +public partial class SkillInstallationReview { - /// Top-level keys whose write landed in settings.json but is shadowed by a value still present in the legacy config.json (config.json wins on read). The write does not take effect until the legacy value is removed. - [JsonPropertyName("shadowedKeys")] - public IList ShadowedKeys { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("action")] + public virtual string Action { get; set; } = string.Empty; } -/// Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsSetRequest -{ - /// Partial user settings to write, as a free-form object keyed by setting name. - [JsonPropertyName("settings")] - public JsonElement Settings { get; set; } -} -/// Validated device-managed settings discovered before a session exists. +/// One reviewed Skill file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsReadResult +public sealed class SkillInstallationFileReview { - /// Discovery or validation error text when managed settings could not be read safely. - [JsonPropertyName("errorMessage")] - public string? ErrorMessage { get; set; } + /// SHA-256 digest of the exact file bytes. + [JsonPropertyName("digest")] + public string Digest { get; set; } = string.Empty; - /// Validated, canonical managed-settings JSON. Omitted when no managed settings were discovered or when discovered settings failed validation. - [JsonPropertyName("settingsJson")] - public JsonElement? SettingsJson { get; set; } -} + /// Whether the file is installed with executable permissions. + [JsonPropertyName("executable")] + public bool Executable { get; set; } -/// One validation finding for a managed-settings document. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsDiagnostic -{ - /// Human-readable description of the finding. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Declared media type for the file. + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } = string.Empty; - /// Dot-separated path of the offending setting, such as `autoTier.overridable`. Empty for the document as a whole. + /// Relative file path within the Skill root. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; - /// Whether the finding rejects the document. - [JsonPropertyName("severity")] - public ManagedSettingsDiagnosticSeverity Severity { get; set; } + /// Exact reviewed file size in bytes. + [JsonPropertyName("sizeBytes")] + public long SizeBytes { get; set; } } -/// One managed-settings channel and the document it delivered. +/// Source identity retained from Agent Finder and the pinned GitHub descriptor. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsLayer +public sealed class SkillInstallationSource { - /// Validated managed-settings document this channel delivered. Absent when the channel delivered none. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// Digest of the descriptor's bundle manifest. + [JsonPropertyName("bundleDigest")] + public string BundleDigest { get; set; } = string.Empty; - /// Channel identifier: `device` (MDM, plist, registry, or managed file), `server` (account or organization policy), or `policyHelper` (session-local helper output, supported by compose). Treat unknown output values as additional channels; more may be added. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; -} + /// Agent Finder materialisation revision identifier. + [JsonPropertyName("catalogRevisionId")] + public string CatalogRevisionId { get; set; } = string.Empty; -/// Lock state and provenance of one managed setting. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingMeta -{ - /// Whether users and repositories may choose a different value. `false` means policy locks the value. - [JsonPropertyName("overridable")] - public bool Overridable { get; set; } + /// Digest of the canonical materialisation descriptor. + [JsonPropertyName("descriptorDigest")] + public string DescriptorDigest { get; set; } = string.Empty; - /// Channel that supplied this scalar value, matching a `layers[].source`: `device`, `server`, or `policyHelper`. These scalar defaults select one winning channel, not a mixed source. Treat unknown values as additional channels; more may be added. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Repository full name, for example owner/name. + [JsonPropertyName("repository")] + public string Repository { get; set; } = string.Empty; + + /// GitHub repository database identifier. + [JsonPropertyName("repositoryId")] + public string RepositoryId { get; set; } = string.Empty; + + /// Agent Finder resource identifier. + [JsonPropertyName("resourceId")] + public string ResourceId { get; set; } = string.Empty; + + /// Pinned Git commit revision. + [JsonPropertyName("revision")] + public string Revision { get; set; } = string.Empty; + + /// Root path within the pinned repository. + [JsonPropertyName("root")] + public string Root { get; set; } = string.Empty; } -/// Per-key lock state and provenance for `ManagedSettingsValues`, with the same field names. Producers emit each typed key in values and meta together; both outer objects are omitted when no typed key is set. +/// A user-facing personal Skill installation location without absolute host paths. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsMeta +public sealed class SkillInstallationLocation { - /// Lock state and provenance of `values.autoTier`. - [JsonPropertyName("autoTier")] - public ManagedSettingMeta? AutoTier { get; set; } + /// Diagnostics-only absolute host path. Hosts must not display it by default. + [JsonPropertyName("diagnosticsAbsolutePath")] + public string? DiagnosticsAbsolutePath { get; set; } - /// Lock state and provenance of `values.model`. - [JsonPropertyName("model")] - public ManagedSettingMeta? Model { get; set; } + /// Safe display label, for example ~/.copilot/skills/run-checks. + [JsonPropertyName("displayLabel")] + public string DisplayLabel { get; set; } = string.Empty; + + /// Path relative to the Copilot home. + [JsonPropertyName("relativePath")] + public string RelativePath { get; set; } = string.Empty; + + /// Installation scope. Agent Finder Skills are installed in the user's personal Copilot home. + [JsonPropertyName("scope")] + public SkillInstallationScope Scope { get; set; } } -/// Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. +/// Review for installing a verified Skill. +/// The install variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsResolvedData +public partial class SkillInstallationReviewInstall : SkillInstallationReview { - /// Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. - [JsonPropertyName("bypassPermissionsDisabled")] - public bool BypassPermissionsDisabled { get; set; } - - /// Whether a session-local permissions layer injected by the SDK host was present. - [JsonPropertyName("clientManaged")] - public bool? ClientManaged { get; set; } - - /// Whether an actual device MDM/plist/registry/file managed-settings layer was present. - [JsonPropertyName("deviceManaged")] - public bool DeviceManaged { get; set; } + /// + [JsonIgnore] + public override string Action => "install"; - /// Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. - [JsonPropertyName("failClosed")] - public bool FailClosed { get; set; } + /// Catalogue identity retained from the bound candidate before consent. + [JsonPropertyName("catalogue")] + public required InstallationCatalogueIdentity Catalogue { get; set; } - /// The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. - [JsonPropertyName("managedKeys")] - public IList ManagedKeys { get => field ??= []; set; } + /// Skill description from SKILL.md when present. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. - [JsonPropertyName("permissionsAllowIntersected")] - public bool? PermissionsAllowIntersected { get; set; } + /// + /// Complete verified SKILL.md content. Planning refuses with review-too-large + /// when this exceeds 262144 UTF-8 bytes; it is never truncated. + /// + [JsonPropertyName("entrypointContent")] + public required string EntrypointContent { get; set; } - /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. - [JsonPropertyName("policyHelperManaged")] - public bool? PolicyHelperManaged { get; set; } + /// Relative path of the verified Skill entrypoint. + [JsonPropertyName("entrypointPath")] + public required string EntrypointPath { get; set; } - /// Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. - [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] - public bool? SandboxEnabledByUndeterminedPolicy { get; set; } + /// Reviewed files and digests. + [JsonPropertyName("files")] + public required IList Files { get; set; } - /// Whether the server (account/org) managed-settings layer was present. - [JsonPropertyName("serverManaged")] - public bool ServerManaged { get; set; } + /// Installing never grants immediate use; the Skill is written disabled. + [JsonPropertyName("installsDisabled")] + public required bool InstallsDisabled { get; set; } - /// The effective (resolved) managed settings values, so clients can render exactly what is enforced. Absent when no managed policy is in force. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// Skill invocation name from SKILL.md. + [JsonPropertyName("name")] + public required string Name { get; set; } - /// Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. + /// Exact verified source identity. [JsonPropertyName("source")] - public ManagedSettingsResolvedSource Source { get; set; } -} + public required SkillInstallationSource Source { get; set; } -/// Typed effective values of managed settings. Each field mirrors the managed-settings schema key of the same name; more keys are added as they are typed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsValues -{ - /// Managed Auto routing preference, used when the selected model is `auto`. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } + /// Exact user-scope target location without an absolute host path. + [JsonPropertyName("target")] + public required SkillInstallationLocation Target { get; set; } - /// Managed default model identifier, as configured. New sessions start with it; it can name a model the account cannot use, so hosts match it against the listed models. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Total reviewed payload size in bytes. + [JsonPropertyName("totalBytes")] + public required long TotalBytes { get; set; } } -/// Effective enterprise managed settings for an account, resolved without a session. +/// Durable verified Skill ownership summary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsResolveResult +public sealed class SkillInstallationSummary { - /// Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. - [JsonPropertyName("account")] - public string? Account { get; set; } - - /// Warnings about unavailable policy sources or a failed refresh served from cache. A cached response is not proof of a successful live fetch; `resolved.failClosed` separately describes enforcement. - [JsonPropertyName("diagnostics")] - public IList Diagnostics { get => field ??= []; set; } + /// Catalogue identity retained at install time. + [JsonPropertyName("catalogue")] + public InstallationCatalogueIdentity Catalogue { get => field ??= new(); set; } - /// Each managed-settings channel consulted, strongest first, with the validated document it delivered before merging. `resolved.settings` is the merged result. More channels may be added over time. - [JsonPropertyName("layers")] - public IList Layers { get => field ??= []; set; } + /// Persisted enablement requested for this installation. + [JsonPropertyName("configuredEnabled")] + public bool ConfiguredEnabled { get; set; } - /// Per-key lock state and provenance for the entries in `values`, using the same key names. - [JsonPropertyName("meta")] - public ManagedSettingsMeta? Meta { get; set; } + /// Exact durable installation receipt identity. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; - /// Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. - [JsonPropertyName("resolved")] - public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } + /// ISO 8601 wall-clock installation time. + [JsonPropertyName("installedAt")] + public string InstalledAt { get; set; } = string.Empty; - /// Typed effective values of managed settings, keyed like the managed-settings schema and already resolved across channels, with the `{ "overridable": ... }` wrapper removed. Present when policy sets at least one typed key. Keys not typed here are available in `resolved.settings`. - [JsonPropertyName("values")] - public ManagedSettingsValues? Values { get; set; } -} + /// Skill invocation name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; -/// RPC data type for ManagedSettingsResolve operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ManagedSettingsResolveRequest -{ - /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Operation that installed this Skill. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. - [JsonPropertyName("gitHubToken")] - public string? GitHubToken { get; set; } + /// Ownership state observed from files and receipts. + [JsonPropertyName("ownershipState")] + public SkillInstallationOwnershipState OwnershipState { get; set; } - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } -} + /// Bound-session load observation. + [JsonPropertyName("sessionState")] + public SkillInstallationSessionState SessionState { get; set; } -/// The authoring JSON schema for managed settings recognized by this runtime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsSchemaResult -{ - /// Version of the runtime that owns this schema. - [JsonPropertyName("runtimeVersion")] - public string RuntimeVersion { get; set; } = string.Empty; + /// Exact retained verified source identity. + [JsonPropertyName("source")] + public SkillInstallationSource Source { get => field ??= new(); set; } - /// JSON schema (draft 2020-12) with descriptive shared `x-composition` annotations, not a complete runtime composition contract. Model, effortLevel, and contextTier remain coupled; use `managedSettings.compose` for the runtime's effective result. - [JsonPropertyName("schema")] - public JsonElement Schema { get; set; } + /// User-facing installation location without an absolute host path. + [JsonPropertyName("target")] + public SkillInstallationLocation Target { get => field ??= new(); set; } } -/// Result of validating a managed-settings document. +/// Review for uninstalling an owned verified Skill. +/// The uninstall variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsValidateResult +public partial class SkillInstallationReviewUninstall : SkillInstallationReview { - /// Errors that reject the document and warnings about content the runtime ignores. - [JsonPropertyName("diagnostics")] - public IList Diagnostics { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Action => "uninstall"; - /// Canonical form of the document the runtime would apply, with unrecognized keys removed. Absent when the document is invalid. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// Catalogue identity retained at install time. + [JsonPropertyName("catalogue")] + public required InstallationCatalogueIdentity Catalogue { get; set; } - /// Whether the runtime would accept the document within the preview resource limits. Always equals whether `settings` is present. An invalid document is rejected as a whole. - [JsonPropertyName("valid")] - public bool Valid { get; set; } -} + /// Files recorded by the installation receipt. + [JsonPropertyName("files")] + public required IList Files { get; set; } -/// A candidate managed-settings document to validate without applying it. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ManagedSettingsValidateRequest -{ - /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. - [JsonPropertyName("content")] - public JsonElement Content { get; set; } + /// Whether current files differ from the receipt. Apply refuses drift. + [JsonPropertyName("filesModified")] + public required bool FilesModified { get; set; } - /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. - [JsonPropertyName("layer")] - public string? Layer { get; set; } + /// Owned installation being removed. + [JsonPropertyName("installation")] + public required SkillInstallationSummary Installation { get; set; } + + /// Total receipt-owned payload size in bytes. + [JsonPropertyName("totalBytes")] + public required long TotalBytes { get; set; } } -/// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. +/// A computed Skill install plan. Nothing has been applied. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsComposeResult +public sealed class SkillInstallPlan { - /// Warnings about ignored content, with paths prefixed by the channel name. - [JsonPropertyName("diagnostics")] - public IList Diagnostics { get => field ??= []; set; } - - /// Only the supplied channels, strongest first, with canonical documents. Empty canonical documents are represented as absent settings, as in live resolution. - [JsonPropertyName("layers")] - public IList Layers { get => field ??= []; set; } + /// Original wall-clock expiry as an ISO 8601 timestamp. + [JsonPropertyName("expiresAt")] + public string ExpiresAt { get; set; } = string.Empty; - /// Per-key lock state and provenance for `values`. - [JsonPropertyName("meta")] - public ManagedSettingsMeta? Meta { get; set; } + /// Original operation identifier returned before confirmation. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// Effective managed settings, in the same shape as `session.managedSettings.get`. - [JsonPropertyName("resolved")] - public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } + /// One-use plan handle, bound to the original candidate authority. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// Typed effective values, as in `managedSettings.resolve`. - [JsonPropertyName("values")] - public ManagedSettingsValues? Values { get; set; } + /// Safe review to present before applying the plan. + [JsonPropertyName("review")] + public SkillInstallationReview Review { get => field ??= new(); set; } } -/// One candidate channel; absent settings represents a channel that delivered no document. +/// A verified Skill installation plan was prepared. +/// The install-planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsComposeLayer +public partial class SkillInstallationManagementOutcomeInstallPlanned : SkillInstallationManagementOutcome { - /// Candidate managed-settings document. Omit when the channel delivered none, as in resolve output. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// + [JsonIgnore] + public override string Kind => "install-planned"; - /// The channel whose candidate document is being supplied. - [JsonPropertyName("source")] - public ManagedSettingsChannel Source { get; set; } + /// Prepared install plan. + [JsonPropertyName("plan")] + public required SkillInstallPlan Plan { get; set; } } -/// Candidate managed-settings documents to merge without applying them. +/// Owned Skill installations were listed. +/// The listed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ManagedSettingsComposeRequest +public partial class SkillInstallationManagementOutcomeListed : SkillInstallationManagementOutcome { - /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. - [JsonPropertyName("layers")] - public IList Layers { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "listed"; + + /// Owned Skill installation summaries. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } } -/// Indicates whether the calling client was registered as the session filesystem provider. +/// Recovery completed and inventory was inspected. +/// The recovered variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSetProviderResult +public partial class SkillInstallationManagementOutcomeRecovered : SkillInstallationManagementOutcome { - /// Whether the provider was set successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// + [JsonIgnore] + public override string Kind => "recovered"; + + /// Owned Skill installation summaries after recovery. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } } -/// Optional capabilities declared by the provider. +/// Interrupted work was safely compensated and the pending marker was cleared. +/// The rolled-back variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSetProviderCapabilities +public partial class SkillInstallationManagementOutcomeRolledBack : SkillInstallationManagementOutcome { - /// Whether the provider supports binary reads and writes through sessionFs.readFileBytes and sessionFs.writeFileBytes. - [JsonPropertyName("binary")] - public bool? Binary { get; set; } + /// + [JsonIgnore] + public override string Kind => "rolled-back"; - /// Whether the provider supports SQLite query/exists operations. - [JsonPropertyName("sqlite")] - public bool? Sqlite { get; set; } + /// Original operation identity. + [JsonPropertyName("operation_id")] + public required string OperationId { get; set; } + + /// Cause of the compensation. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } } -/// Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. +/// A computed Skill uninstall plan. Nothing has been removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionFsSetProviderRequest +public sealed class SkillUninstallPlan { - /// Optional capabilities declared by the provider. - [JsonPropertyName("capabilities")] - public SessionFsSetProviderCapabilities? Capabilities { get; set; } + /// Original wall-clock expiry as an ISO 8601 timestamp. + [JsonPropertyName("expiresAt")] + public string ExpiresAt { get; set; } = string.Empty; - /// Path conventions used by this filesystem. - [JsonPropertyName("conventions")] - public SessionFsSetProviderConventions Conventions { get; set; } + /// Owned Skill installation being removed. + [JsonPropertyName("installation")] + public SkillInstallationSummary Installation { get => field ??= new(); set; } - /// Absolute initial working directory for sessions. Registering the provider establishes this path as the root of its virtual namespace; the runtime does not require the provider to materialize or stat it before creating a session. - [JsonPropertyName("initialCwd")] - public string InitialCwd { get; set; } = string.Empty; + /// Original removal operation identifier returned before confirmation. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// Path within each session's SessionFs where the runtime stores files for that session. - [JsonPropertyName("sessionStatePath")] - public string SessionStatePath { get; set; } = string.Empty; + /// One-use uninstall plan handle. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// Safe review to present before applying removal. + [JsonPropertyName("review")] + public SkillInstallationReview Review { get => field ??= new(); set; } } -/// Indicates whether the calling client was registered as the LLM inference provider. +/// An owned Skill uninstall plan was prepared. +/// The uninstall-planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceSetProviderResult +public partial class SkillInstallationManagementOutcomeUninstallPlanned : SkillInstallationManagementOutcome { - /// Whether the provider was set successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// + [JsonIgnore] + public override string Kind => "uninstall-planned"; + + /// Prepared uninstall plan. + [JsonPropertyName("plan")] + public required SkillUninstallPlan Plan { get; set; } } -/// Whether the start frame was accepted. +/// Status snapshot from the original connection, independent of new-work account availability. +/// Polymorphic base type discriminated by phase. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpResponseStartResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "phase", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationOperationStatusPreparing), "preparing")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusPrepared), "prepared")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusRevalidating), "revalidating")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusApplying), "applying")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusCompleted), "completed")] +public partial class SkillInstallationOperationStatus { - /// True when the response start was matched to a pending request; false when unknown. - [JsonPropertyName("accepted")] - public bool Accepted { get; set; } + /// The type discriminator. + [JsonPropertyName("phase")] + public virtual string Phase { get; set; } = string.Empty; } -/// Response head. + +/// Original operation progress discriminator. +/// The preparing variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LlmInferenceHttpResponseStartRequest +public partial class SkillInstallationOperationStatusPreparing : SkillInstallationOperationStatus { - /// HTTP response headers, preserving multiple values per name. - [JsonPropertyName("headers")] - public IDictionary> Headers { get => field ??= new Dictionary>(); set; } - - /// Matches the requestId from the originating httpRequestStart frame. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Phase => "preparing"; - /// HTTP status code. - [JsonPropertyName("status")] - public long Status { get; set; } + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Optional HTTP status reason phrase. - [JsonPropertyName("statusText")] - public string? StatusText { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Whether the chunk was accepted. +/// Original operation progress discriminator. +/// The prepared variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpResponseChunkResult +public partial class SkillInstallationOperationStatusPrepared : SkillInstallationOperationStatus { - /// True when the chunk was matched to a pending request; false when unknown. - [JsonPropertyName("accepted")] - public bool Accepted { get; set; } -} + /// + [JsonIgnore] + public override string Phase => "prepared"; -/// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpResponseChunkError -{ - /// Optional machine-readable error code. - [JsonPropertyName("code")] - public string? Code { get; set; } + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Human-readable failure description. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// A response body chunk or terminal error. +/// Original operation progress discriminator. +/// The awaiting-confirmation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LlmInferenceHttpResponseChunkRequest +public partial class SkillInstallationOperationStatusAwaitingConfirmation : SkillInstallationOperationStatus { - /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. - [JsonPropertyName("binary")] - public bool? Binary { get; set; } - - /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty (e.g. when the response body is empty: send a single chunk with empty data and end=true). - [JsonPropertyName("data")] - public string Data { get; set; } = string.Empty; - - /// When true, this is the final body chunk for the response. The runtime treats the response body as complete after receiving an end-marked chunk. - [JsonPropertyName("end")] - public bool? End { get; set; } + /// + [JsonIgnore] + public override string Phase => "awaiting-confirmation"; - /// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. - [JsonPropertyName("error")] - public LlmInferenceHttpResponseChunkError? Error { get; set; } + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Matches the requestId from the originating httpRequestStart frame. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Pre-resolved working-directory context for session startup. +/// Original operation progress discriminator. +/// The revalidating variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionContext +public partial class SkillInstallationOperationStatusRevalidating : SkillInstallationOperationStatus { - /// Active git branch. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Most recent working directory for this session. - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; - - /// Git repository root, if the cwd was inside a git repo. - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// + [JsonIgnore] + public override string Phase => "revalidating"; - /// Repository host type. - [JsonPropertyName("hostType")] - public SessionContextHostType? HostType { get; set; } + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Repository slug in `owner/name` form, when known. - [JsonPropertyName("repository")] - public string? Repository { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// GitHub repository the remote session belongs to. +/// Original operation progress discriminator. +/// The applying variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteSessionMetadataRepository +public partial class SkillInstallationOperationStatusApplying : SkillInstallationOperationStatus { - /// Branch associated with the remote session. - [JsonPropertyName("branch")] - public string Branch { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Phase => "applying"; - /// Repository name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether cancellation has been requested; already-started effects require recovery. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Repository owner. - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Remote session metadata for the session to hand off (typically obtained from `sessions.list` with `source: "remote"`). +/// Terminal verified Skill mutation result. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteSessionMetadataValue +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationOutcomeInstalled), "installed")] +[JsonDerivedType(typeof(SkillInstallationOutcomeUninstalled), "uninstalled")] +[JsonDerivedType(typeof(SkillInstallationOutcomeRolledBack), "rolled-back")] +[JsonDerivedType(typeof(SkillInstallationOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(SkillInstallationOutcomeDeclined), "declined")] +[JsonDerivedType(typeof(SkillInstallationOutcomeCancelled), "cancelled")] +[JsonDerivedType(typeof(SkillInstallationOutcomeRefused), "refused")] +public partial class SkillInstallationOutcome { - /// Most recent working directory context. - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. - [JsonPropertyName("hostActivity")] - public string? HostActivity { get; set; } - /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. - [JsonPropertyName("hostStatus")] - public RemoteSessionHostStatus? HostStatus { get; set; } +/// The verified Skill was installed disabled. +/// The installed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOutcomeInstalled : SkillInstallationOutcome +{ + /// + [JsonIgnore] + public override string Kind => "installed"; - /// Always true for remote sessions. - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } + /// Durable installed Skill summary. + [JsonPropertyName("installation")] + public required SkillInstallationSummary Installation { get; set; } +} - /// Last-modified time as an ISO 8601 timestamp. - [JsonPropertyName("modifiedTime")] - public string ModifiedTime { get; set; } = string.Empty; +/// The owned Skill was removed. +/// The uninstalled variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOutcomeUninstalled : SkillInstallationOutcome +{ + /// + [JsonIgnore] + public override string Kind => "uninstalled"; - /// Optional human-friendly name set via /rename. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Removed installation identity. + [JsonPropertyName("installationId")] + public required string InstallationId { get; set; } - /// Pull request number associated with the session. - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } + /// Original removal operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } +} - /// Backing remote session IDs (most recent first). - [JsonPropertyName("remoteSessionIds")] - public IList RemoteSessionIds { get => field ??= []; set; } +/// The durable transaction was aborted or fully compensated. +/// The rolled-back variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOutcomeRolledBack : SkillInstallationOutcome +{ + /// + [JsonIgnore] + public override string Kind => "rolled-back"; - /// GitHub repository the remote session belongs to. - [JsonPropertyName("repository")] - public RemoteSessionMetadataRepository Repository { get => field ??= new(); set; } + /// Original operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } - /// Original remote resource identifier (task ID or PR node ID). - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Cause of the fully aborted or compensated operation. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } +} - /// Stable session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; +/// A write may have completed. Recover and inspect durable state before retrying. +/// The recovery-required variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOutcomeRecoveryRequired : SkillInstallationOutcome +{ + /// + [JsonIgnore] + public override string Kind => "recovery-required"; - /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. - [JsonPropertyName("staleAt")] - public string? StaleAt { get; set; } + /// Operation whose durable result must be recovered and inspected. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } +} - /// Session creation time as an ISO 8601 timestamp. - [JsonPropertyName("startTime")] - public string StartTime { get; set; } = string.Empty; +/// The user declined the confirmation request. +/// The declined variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOutcomeDeclined : SkillInstallationOutcome +{ + /// + [JsonIgnore] + public override string Kind => "declined"; - /// Server-side task state returned by GitHub. - [JsonPropertyName("state")] - public string? State { get; set; } + /// Original operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } +} - /// Short summary of the session, when one has been derived. - [JsonPropertyName("summary")] - public string? Summary { get; set; } +/// The operation was cancelled before a terminal mutation. +/// The cancelled variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOutcomeCancelled : SkillInstallationOutcome +{ + /// + [JsonIgnore] + public override string Kind => "cancelled"; - /// Whether the remote task originated from CCA or CLI `--remote`. - [JsonPropertyName("taskType")] - public RemoteSessionMetadataTaskType? TaskType { get; set; } + /// Original operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// `sessions.open` handoff progress update with step, status, and optional message. +/// The operation was refused without applying changes. +/// The refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsOpenProgress +public partial class SkillInstallationOutcomeRefused : SkillInstallationOutcome { - /// Optional step message. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// + [JsonIgnore] + public override string Kind => "refused"; - /// Step status. - [JsonPropertyName("status")] - public SessionsOpenProgressStatus Status { get; set; } + /// Present once an operation has been allocated. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("operationId")] + public string? OperationId { get; set; } - /// Handoff step. - [JsonPropertyName("step")] - public SessionsOpenProgressStep Step { get; set; } + /// Bounded refusal reason. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } } -/// Result of opening a session. +/// Original operation progress discriminator. +/// The completed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionOpenResult +public partial class SkillInstallationOperationStatusCompleted : SkillInstallationOperationStatus { - /// Remote session metadata, present when status is `connected`. - [JsonPropertyName("metadata")] - public RemoteSessionMetadataValue? Metadata { get; set; } - - /// Handoff progress steps, present when status is `handed_off`. - [JsonPropertyName("progress")] - public IList? Progress { get; set; } - - /// Remote session ID, present when status is `connected`. - [JsonPropertyName("remoteSessionId")] - public string? RemoteSessionId { get; set; } + /// + [JsonIgnore] + public override string Phase => "completed"; - /// Opened session ID. Omitted when status is `not_found`. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// Whether cancellation was requested before the terminal result. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Startup prompts queued by user-level hook configs at session creation. Only populated when status is `created`; resumed sessions return an empty array. - [JsonPropertyName("startupPrompts")] - public IList? StartupPrompts { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } - /// Outcome of the open request. - [JsonPropertyName("status")] - public SessionsOpenStatus Status { get; set; } + /// Immutable terminal receipt. + [JsonPropertyName("outcome")] + public required SkillInstallationOutcome Outcome { get; set; } } -/// Identifier and optional friendly name assigned to the newly forked session. +/// Original-connection operation snapshot. +/// The operation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsForkResult +public partial class SkillInstallationManagementOutcomeOperation : SkillInstallationManagementOutcome { - /// Friendly name assigned to the forked session, if any. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// + [JsonIgnore] + public override string Kind => "operation"; - /// The new forked session's ID. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Operation status. + [JsonPropertyName("operation")] + public required SkillInstallationOperationStatus Operation { get; set; } } -/// Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. +/// Enablement changed and the selected session was reconciled. +/// The enabled-changed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsForkRequest +public partial class SkillInstallationManagementOutcomeEnabledChanged : SkillInstallationManagementOutcome { - /// Optional friendly name to assign to the forked session. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// + [JsonIgnore] + public override string Kind => "enabled-changed"; - /// Source session ID to fork from. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Safe reload or reconciliation diagnostics. + [JsonPropertyName("diagnostics")] + public required IList Diagnostics { get; set; } - /// Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. - [JsonPropertyName("toEventId")] - public string? ToEventId { get; set; } + /// Updated installation summary. + [JsonPropertyName("installation")] + public required SkillInstallationSummary Installation { get; set; } } -/// Repository associated with the connected remote session. +/// The management request was refused. +/// The refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectedRemoteSessionMetadataRepository +public partial class SkillInstallationManagementOutcomeRefused : SkillInstallationManagementOutcome { - /// Branch associated with the remote session. - [JsonPropertyName("branch")] - public string Branch { get; set; } = string.Empty; - - /// Repository name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "refused"; - /// Repository owner or organization login. - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; + /// Bounded refusal reason. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } } -/// Metadata for a connected remote session. +/// The outcome variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectedRemoteSessionMetadata +public partial class SkillInstallationManagementResultOutcome : SkillInstallationManagementResult { - /// Neutral SDK discriminator for the connected remote session kind. - [JsonPropertyName("kind")] - public ConnectedRemoteSessionMetadataKind Kind { get; set; } - - /// Last session update time as an ISO 8601 string. - [JsonPropertyName("modifiedTime")] - public DateTimeOffset ModifiedTime { get; set; } + /// + [JsonIgnore] + public override string Kind => "outcome"; - /// Optional friendly session name. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Capabilities honoured for this request. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// Pull request number associated with the session. - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } + /// Observed management outcome. + [JsonPropertyName("outcome")] + public required SkillInstallationManagementOutcome Outcome { get; set; } +} - /// Repository associated with the connected remote session. - [JsonPropertyName("repository")] - public ConnectedRemoteSessionMetadataRepository Repository { get => field ??= new(); set; } +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationManagementResultNegotiationRefused : SkillInstallationManagementResult +{ + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; - /// Original remote resource identifier. - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// SDK session ID for the connected remote session. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } - /// Remote session staleness deadline as an ISO 8601 string. - [JsonPropertyName("staleAt")] - public DateTimeOffset? StaleAt { get; set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// Session start time as an ISO 8601 string. - [JsonPropertyName("startTime")] - public DateTimeOffset StartTime { get; set; } + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } - /// Remote session state returned by the backing service. - [JsonPropertyName("state")] - public string? State { get; set; } + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } - /// Optional session summary. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// Remote session connection result. +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteSessionConnectionResult +public partial class SkillInstallationManagementResultInvalidRequest : SkillInstallationManagementResult { - /// Metadata for a connected remote session. - [JsonPropertyName("metadata")] - public ConnectedRemoteSessionMetadata Metadata { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "invalid-request"; - /// SDK session ID for the connected remote session. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } -/// Remote session connection parameters. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectRemoteSessionParams -{ - /// Session ID to connect to. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Local or remote session metadata entry. Narrow on `isRemote` to access source-specific fields. -/// Data type discriminated by isRemote. +/// Side-effect-free planning of one verified Agent Finder Skill candidate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionListEntry +internal sealed class SkillPlanInstallRequest { - /// The boolean discriminator. - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } - - /// Runtime client name that created/last resumed this session. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Fresh single-use AI skill candidate handle returned by a bound catalogue search. + [JsonPropertyName("candidateHandle")] + public string CandidateHandle { get; set; } = string.Empty; - /// Pre-resolved working-directory context for session startup. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } + /// Required authenticated bound catalogue and Skill installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("hostActivity")] - public string? HostActivity { get; set; } + /// Existing local session attached to this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; +} - /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("hostStatus")] - public RemoteSessionHostStatus? HostStatus { get; set; } +/// Skill installation result with the honoured contract, or a typed request/negotiation refusal. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationResultOutcome), "outcome")] +[JsonDerivedType(typeof(SkillInstallationResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(SkillInstallationResultInvalidRequest), "invalid-request")] +public partial class SkillInstallationResult +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// True for detached maintenance sessions that should be hidden from normal resume lists. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("isDetached")] - public bool? IsDetached { get; set; } - /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mcTaskId")] - public string? McTaskId { get; set; } +/// The outcome variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationResultOutcome : SkillInstallationResult +{ + /// + [JsonIgnore] + public override string Kind => "outcome"; - /// Last-modified time of the session's persisted state, as ISO 8601. - [JsonPropertyName("modifiedTime")] - public required string ModifiedTime { get; set; } + /// Capabilities honoured for this request. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// Optional human-friendly name set via /rename. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Terminal operation outcome. + [JsonPropertyName("outcome")] + public required SkillInstallationOutcome Outcome { get; set; } +} - /// Pull request number associated with the session. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationResultNegotiationRefused : SkillInstallationResult +{ + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; - /// Backing remote session IDs (most recent first). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("remoteSessionIds")] - public IList? RemoteSessionIds { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// GitHub repository the remote session belongs to. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("repository")] - public RemoteSessionMetadataRepository? Repository { get; set; } + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } - /// Original remote resource identifier (task ID or PR node ID). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// Stable session identifier. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } - /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("staleAt")] - public string? StaleAt { get; set; } + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } - /// Session creation time as an ISO 8601 timestamp. - [JsonPropertyName("startTime")] - public required string StartTime { get; set; } + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } +} - /// Server-side task state returned by GitHub. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("state")] - public string? State { get; set; } +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationResultInvalidRequest : SkillInstallationResult +{ + /// + [JsonIgnore] + public override string Kind => "invalid-request"; - /// Short summary of the session, when one has been derived. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } - /// Whether the remote task originated from CCA or CLI `--remote`. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("taskType")] - public RemoteSessionMetadataTaskType? TaskType { get; set; } + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Sessions matching the filter, ordered most-recently-modified first. +/// Applies exactly one retained verified Skill installation plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionList +internal sealed class SkillApplyInstallRequest { - /// Sessions ordered most-recently-modified first. Discriminated by `isRemote`. - [JsonPropertyName("sessions")] - public IList Sessions { get => field ??= []; set; } + /// Required authenticated bound catalogue and Skill installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } + + /// Opaque original plan, consumed once. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// Same existing selected session as planning. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Optional filter applied to the returned sessions. +/// Read-only preparation of one owned Skill removal under fresh selected-session authority. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionListFilter +internal sealed class SkillPlanUninstallRequest { - /// Match sessions whose context.branch equals this value. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Match sessions whose context.cwd equals this value. - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Match sessions whose context.gitRoot equals this value. - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// Exact receipt to inspect. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; - /// Match sessions whose context.repository equals this value. - [JsonPropertyName("repository")] - public string? Repository { get; set; } + /// Existing selected local session on this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Optional source filter, metadata-load limit, and context filter applied to the returned sessions. +/// One-use application of the exact retained Skill removal plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsListRequest +internal sealed class SkillApplyUninstallRequest { - /// Optional filter applied to the returned sessions. - [JsonPropertyName("filter")] - public SessionListFilter? Filter { get; set; } - - /// When true, include detached maintenance sessions. Defaults to false for user-facing session lists. - [JsonPropertyName("includeDetached")] - public bool? IncludeDetached { get; set; } - - /// When provided, only the first N local sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every local session. Has no effect on remote entries (which always carry their full shape). - [JsonPropertyName("metadataLimit")] - public long? MetadataLimit { get; set; } + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Which session sources to include. Defaults to `local` for backward compatibility. - [JsonPropertyName("source")] - public SessionSource? Source { get; set; } + /// Opaque original removal plan, consumed once. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// Only meaningful when `source` includes remote. When true, propagates errors from the remote service instead of silently returning an empty remote list. Defaults to false. - [JsonPropertyName("throwOnError")] - public bool? ThrowOnError { get; set; } + /// Same existing selected session as removal preparation. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Persisted local session metadata, including identifiers, timestamps, summary/name, client, context, detached state, and task ID. +/// Server-side skill metadata, including name, description, source, enabled/invocable state, path, project path, and argument hint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LocalSessionMetadataValue +public sealed class ServerSkill { - /// Runtime client name that created/last resumed this session. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } - - /// Pre-resolved working-directory context for session startup. - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } - - /// True for detached maintenance sessions that should be hidden from normal resume lists. - [JsonPropertyName("isDetached")] - public bool? IsDetached { get; set; } + /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. + [JsonPropertyName("argumentHint")] + public string? ArgumentHint { get; set; } - /// Always false for local sessions. - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } + /// Canonical slash command name used to invoke the skill, without the leading '/'. + [JsonPropertyName("commandName")] + public string? CommandName { get; set; } - /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. - [JsonPropertyName("mcTaskId")] - public string? McTaskId { get; set; } + /// Description of what the skill does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Last-modified time of the session's persisted state, as ISO 8601. - [JsonPropertyName("modifiedTime")] - public string ModifiedTime { get; set; } = string.Empty; + /// Whether the skill is currently enabled (based on global config). + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Optional human-friendly name set via /rename. + /// Unique identifier for the skill. [JsonPropertyName("name")] - public string? Name { get; set; } + public string Name { get; set; } = string.Empty; - /// Stable session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Absolute path to the skill file. + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Session creation time as an ISO 8601 timestamp. - [JsonPropertyName("startTime")] - public string StartTime { get; set; } = string.Empty; + /// The project path this skill belongs to (only for project/inherited skills). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } - /// Short summary of the session, when one has been derived. - [JsonPropertyName("summary")] - public string? Summary { get; set; } -} + /// Source location type (e.g., project, personal-copilot, plugin, builtin). + [JsonPropertyName("source")] + public SkillSource Source { get; set; } -/// Persisted local session metadata when the session exists. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetMetadataResult -{ - /// Local session metadata, omitted when the session does not exist. - [JsonPropertyName("session")] - public LocalSessionMetadataValue? Session { get; set; } + /// Whether the skill can be invoked by the user as a slash command. + [JsonPropertyName("userInvocable")] + public bool UserInvocable { get; set; } } -/// Session ID whose persisted metadata should be read. +/// Skills discovered across global and project sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetMetadataRequest +public sealed class ServerSkillList { - /// Session ID to inspect. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Messages for skills that failed to load (e.g. malformed SKILL.md). Empty when host skills are excluded so host-local paths are not disclosed to multitenant callers. + [JsonPropertyName("errors")] + public IList? Errors { get; set; } + + /// All discovered skills across all sources. + [JsonPropertyName("skills")] + public IList Skills { get => field ??= []; set; } } -/// Client metadata outcome for one requested local session. -/// Polymorphic base type discriminated by status. +/// Optional project paths and additional skill directories to include in discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "status", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SessionsClientMetadataEntryOk), "ok")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryNotFound), "notFound")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryCorrupt), "corrupt")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryUnsupportedVersion), "unsupportedVersion")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryUnavailable), "unavailable")] -public partial class SessionsClientMetadataEntry +internal sealed class SkillsDiscoverRequest { - /// The type discriminator. - [JsonPropertyName("status")] - public virtual string Status { get; set; } = string.Empty; -} + /// When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. + [JsonPropertyName("excludeHostSkills")] + public bool? ExcludeHostSkills { get; set; } + + /// Optional skill scan paths to exclude from discovery. + [JsonPropertyName("ignoredSkillsLocations")] + public IList? IgnoredSkillsLocations { get; set; } + /// Optional list of project directory paths to scan for project-scoped skills. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } -/// The ok variant of . + /// Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("skillDirectories")] + public IList? SkillDirectories { get; set; } +} + +/// Canonical directory where skills can be discovered or created, with scope, preference, and optional project path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryOk : SessionsClientMetadataEntry +public sealed class SkillDiscoveryPath { - /// - [JsonIgnore] - public override string Status => "ok"; + /// Absolute path of the create/discovery target (may not exist on disk yet). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Validated client metadata, possibly empty or projected to requested keys. - [JsonPropertyName("metadata")] - public required IDictionary Metadata { get; set; } + /// Whether this is the canonical directory to create a new skill in its tier. At most one entry per tier is preferred; the `personal-agents` and `custom` scopes are never preferred. + [JsonPropertyName("preferredForCreation")] + public bool PreferredForCreation { get; set; } - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// The input project path this directory was derived from (only for project scope). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } + + /// Which tier this directory belongs to. + [JsonPropertyName("scope")] + public SkillDiscoveryScope Scope { get; set; } } -/// The notFound variant of . +/// Canonical locations where skills can be created so the runtime will recognize them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryNotFound : SessionsClientMetadataEntry +public sealed class SkillDiscoveryPathList { - /// - [JsonIgnore] - public override string Status => "notFound"; - - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// Canonical skill create/discovery directories, in priority order. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } } -/// The corrupt variant of . +/// Optional project paths to enumerate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryCorrupt : SessionsClientMetadataEntry +public sealed class SkillsGetDiscoveryPathsRequest { - /// - [JsonIgnore] - public override string Status => "corrupt"; + /// When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + [JsonPropertyName("excludeHostSkills")] + public bool? ExcludeHostSkills { get; set; } - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// Optional skill scan paths to exclude from discovery. + [JsonPropertyName("ignoredSkillsLocations")] + public IList? IgnoredSkillsLocations { get; set; } + + /// Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } + + /// Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("skillDirectories")] + public IList? SkillDirectories { get; set; } } -/// The unsupportedVersion variant of . +/// Inventory request under an explicitly selected existing session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryUnsupportedVersion : SessionsClientMetadataEntry +internal sealed class SkillInstallationsRequest { - /// - [JsonIgnore] - public override string Status => "unsupportedVersion"; + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// Existing selected local session on this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// The unavailable variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryUnavailable : SessionsClientMetadataEntry -{ - /// - [JsonIgnore] - public override string Status => "unavailable"; - - /// Filesystem or provider error code. Clients should not assume every provider uses operating-system error codes. - [JsonPropertyName("code")] - public required string Code { get; set; } - - /// Human-readable diagnostic message. Not stable for programmatic matching. - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } -} - -/// Bounded batch request for client-owned metadata from persisted local sessions. +/// Existing-operation control. A new session selector is deliberately not accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetClientMetadataRequest +internal sealed class SkillInstallationOperationRequest { - /// Case-sensitive keys to project from each valid bag. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Omit to return every entry. - [JsonPropertyName("keys")] - public IList? Keys { get; set; } + /// Required authenticated bound Skill installation capability. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Session IDs to inspect. Results preserve this order. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } + /// Exact runtime-issued operation ID on the original connection. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; } -/// Batch of session events returned by a read, with cursor and continuation metadata. +/// Persisted enablement update for one owned Skill installation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EventsReadResult +internal sealed class SkillSetEnabledRequest { - /// Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue from where this read left off. Always present, even when no events were returned. For a backward read this cursor pages toward OLDER events; keep passing `direction: backward` with it (the cursor is also self-describing, so backward paging continues correctly). - [JsonPropertyName("cursor")] - public string Cursor { get; set; } = string.Empty; + /// Required authenticated bound Skill installation capability. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Cursor status: 'ok' means the cursor was applied successfully. For session.eventLog.read, 'expired' means the cursor referred to an event that no longer exists in active history and the read fell back to a boundary of the remaining history: the beginning for a forward read or the newest window for a backward read. That fallback may overlap already rendered events, so active-session consumers should reset, rebase, or deduplicate before continuing. sessions.readPersistedEvents has stricter snapshot semantics: 'expired' returns an empty terminal page and never switches to a replacement journal generation. Other persisted-read I/O failures are RPC errors with diagnostics, not cursor expiry. - [JsonPropertyName("cursorStatus")] - public EventsCursorStatus CursorStatus { get; set; } + /// Persisted enablement value. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Session events for this batch, merged into a single stream in creation order: durable (persisted) events and ephemeral events interleave exactly as they were emitted. Set `includeEphemeral: false` to receive only durable events. Ephemeral events are never replayable once pruned from the in-memory ring, so a consumer that needs them should keep reading with a non-zero `waitMs`. For a backward (tail-first) read, the returned window contains persisted events only, still in chronological (oldest-to-newest) append order. - [JsonPropertyName("events")] - public IList Events { get => field ??= []; set; } + /// Exact receipt identity to update. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; - /// True when more events are available in the read's direction. For a backward read, true means older persisted events remain before the returned window. A persisted-event page may contain fewer than `max` events because of its byte budget while still reporting hasMore true; continue according to this flag rather than the event count. - [JsonPropertyName("hasMore")] - public bool HasMore { get; set; } + /// Existing selected local session to reconcile after persistence. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Pagination options for reading an inactive or active local session's persisted event journal. +/// Skill names to mark as disabled in global configuration, replacing any previous list. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsReadPersistedEventsRequest +internal sealed class SkillsConfigSetDisabledSkillsRequest { - /// Opaque, process-local, single-use cursor returned by the previous persisted-event read. Omit on the first call and issue continuations sequentially; reusing the same cursor returns an expired terminal page. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } - - /// Direction to page through persisted history. Forward starts at the beginning; backward starts with the newest events. Events in each page remain chronological. This selects the initial read only; a continuation always uses the direction bound into its cursor. - [JsonPropertyName("direction")] - public EventsReadDirection? Direction { get; set; } - - /// Maximum number of events to return in this batch (1–1000, default 200). Pages may contain fewer events to keep the serialized event array within a soft 1 MiB budget including resolved binary assets; one oversized event is returned alone to guarantee progress. - [JsonPropertyName("max")] - public long? Max { get; set; } - - /// Session ID whose persisted event journal should be read. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// List of skill names to disable. + [JsonPropertyName("disabledSkills")] + public IList DisabledSkills { get => field ??= []; set; } } -/// Recent local session IDs that contain user-visible history. +/// Adds or removes a single skill from the global disabled list, leaving every other entry untouched. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsListNonEmptySessionIdsResult +internal sealed class SkillsConfigSetSkillDisabledRequest { - /// Session IDs ordered newest-first. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } -} + /// True to disable the skill, false to enable it. + [JsonPropertyName("disabled")] + public bool Disabled { get; set; } -/// Limit for non-empty local session IDs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsListNonEmptySessionIdsRequest -{ - /// Maximum number of session IDs to return. - [JsonPropertyName("limit")] - public long? Limit { get; set; } + /// Name of the skill to add to or remove from the disabled list. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// ID of the local session bound to the given GitHub task, or omitted when none. +/// Outcome of a catalog.search call: either bounded inert candidates, or one typed refusal. Never a partial success. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsFindByTaskIDResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogSearchResultSucceeded), "succeeded")] +[JsonDerivedType(typeof(CatalogSearchResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(CatalogSearchResultUnsupportedKind), "unsupported-kind")] +[JsonDerivedType(typeof(CatalogSearchResultInvalidRequest), "invalid-request")] +[JsonDerivedType(typeof(CatalogSearchResultAuthenticationRequired), "authentication-required")] +[JsonDerivedType(typeof(CatalogSearchResultPolicyRejected), "policy-rejected")] +[JsonDerivedType(typeof(CatalogSearchResultNetworkFailure), "network-failure")] +[JsonDerivedType(typeof(CatalogSearchResultUnsafeRetrieval), "unsafe-retrieval")] +[JsonDerivedType(typeof(CatalogSearchResultMalformedCard), "malformed-card")] +[JsonDerivedType(typeof(CatalogSearchResultContractViolation), "contract-violation")] +[JsonDerivedType(typeof(CatalogSearchResultUnavailable), "unavailable")] +public partial class CatalogSearchResult { - /// Omitted when no local session is bound to that GitHub task. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// GitHub task ID to look up. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsFindByTaskIDRequest -{ - /// GitHub task ID to look up. - [JsonPropertyName("taskId")] - public string TaskId { get; set; } = string.Empty; -} -/// Session ID matching the prefix, omitted when no unique match exists. +/// One inert catalog result, represented as an MCP server, discovery-only AI skill, or opt-in Agent Plugin variant so kind, media type, provenance, and available operations cannot contradict each other. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsFindByPrefixResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogCandidateMcpServer), "mcp-server")] +[JsonDerivedType(typeof(CatalogCandidateAiSkill), "ai-skill")] +[JsonDerivedType(typeof(CatalogCandidatePlugin), "plugin")] +public partial class CatalogCandidate { - /// Omitted when no unique session matches the prefix (no match or ambiguous). - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// UUID prefix to resolve to a unique session ID. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsFindByPrefixRequest -{ - /// UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. - [JsonPropertyName("prefix")] - public string Prefix { get; set; } = string.Empty; -} -/// Most-relevant session ID for the supplied context, or omitted when no sessions exist. +/// Where and when an MCP server catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsGetLastForContextResult +public sealed class CatalogMcpServerCandidateProvenance { - /// Most-relevant session ID for the supplied context, or omitted when no sessions exist. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } -} + /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. + [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("authority")] + public string Authority { get; set; } = string.Empty; -/// Optional working-directory context used to score session relevance. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetLastForContextRequest -{ - /// Optional working-directory context used to score session relevance. When omitted the most-recently-modified session wins. - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } -} + /// JSON MCP media type advertised for the referenced card. + [JsonPropertyName("mediaType")] + public McpServerCardMediaType MediaType { get; set; } -/// Absolute path to the session's events.jsonl file on disk. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetEventFilePathResult -{ - /// Absolute path to the session's events.jsonl file. - [JsonPropertyName("filePath")] - public string FilePath { get; set; } = string.Empty; + /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. + [JsonPropertyName("observedAt")] + public string ObservedAt { get; set; } = string.Empty; } -/// Session ID whose event-log file path to compute. +/// Where a candidate's card came from. Exactly one of a URL or embedded data: the union has no variant carrying both, and no variant carrying neither, so the rule holds structurally rather than by validation. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetEventFilePathRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogCandidateSourceUrl), "url")] +[JsonDerivedType(typeof(CatalogCandidateSourceEmbedded), "embedded")] +public partial class CatalogCandidateSource { - /// Session ID whose event-log file path to compute. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Map of sessionId -> on-disk size in bytes for each session's workspace directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSizes -{ - /// Map of sessionId -> on-disk size in bytes for the session's workspace directory. - [JsonPropertyName("sizes")] - public IDictionary Sizes { get => field ??= new Dictionary(); set; } -} -/// Session IDs from the input set that are currently in use by another process. +/// Candidate whose card is retrieved from a URL through the runtime's hardened fetch boundary. +/// The url variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsCheckInUseResult +public partial class CatalogCandidateSourceUrl : CatalogCandidateSource { - /// Session IDs from the input set that are currently held by another running process via an alive lock file. - [JsonPropertyName("inUse")] - public IList InUse { get => field ??= []; set; } -} + /// + [JsonIgnore] + public override string Kind => "url"; -/// Session IDs to test for live in-use locks. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsCheckInUseRequest -{ - /// Session IDs to test for live in-use locks. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } + /// Card URL as advertised. Inert untrusted data: the runtime retrieves it only through its own hardened boundary, and it is never logged. + [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("url")] + public required string Url { get; set; } } -/// The session's persisted remote-steerable flag, or omitted when no value has been persisted. +/// Candidate whose card reference arrived inline. The document and its content-derived properties stay behind the runtime boundary. +/// The embedded variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetPersistedRemoteSteerableResult +public partial class CatalogCandidateSourceEmbedded : CatalogCandidateSource { - /// The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted. - [JsonPropertyName("remoteSteerable")] - public bool? RemoteSteerable { get; set; } + /// + [JsonIgnore] + public override string Kind => "embedded"; } -/// Session ID to look up the persisted remote-steerable flag for. +/// An inert MCP server catalog result. Every free-text field is untrusted external data and must never be treated as an instruction, and the handle is the only way to refer to the candidate in a later operation. +/// The mcp-server variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetPersistedRemoteSteerableRequest +public partial class CatalogCandidateMcpServer : CatalogCandidate { - /// Session ID to look up the persisted remote-steerable flag for. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Kind => "mcp-server"; -/// 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. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsCloseResult -{ -} + /// Description taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } -/// Session ID to close. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsCloseRequest -{ - /// Session ID to close. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Display name taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } -/// Map of sessionId -> bytes freed by removing the session's workspace directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionBulkDeleteResult -{ - /// Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). - [JsonPropertyName("freedBytes")] - public IDictionary FreedBytes { get => field ??= new Dictionary(); set; } -} + /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. + [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("handle")] + public required string Handle { get; set; } -/// Session IDs to close, deactivate, and delete from disk. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsBulkDeleteRequest -{ - /// Session IDs to close, deactivate, and delete from disk. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } + /// ISO 8601 timestamp after which the handle is stale and will be rejected. + [JsonPropertyName("handleExpiresAt")] + public required string HandleExpiresAt { get; set; } + + /// Whether this MCP server can be planned for installation, and if policy prevents it. + [JsonPropertyName("installability")] + public required CatalogMcpServerInstallability Installability { get; set; } + + /// JSON MCP media type of the underlying card. + [JsonPropertyName("mediaType")] + public required McpServerCardMediaType MediaType { get; set; } + + /// Where the catalog reference was observed, without the card itself or any content digest. + [JsonPropertyName("provenance")] + public required CatalogMcpServerCandidateProvenance Provenance { get; set; } + + /// Publisher taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("publisher")] + public string? Publisher { get; set; } + + /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. + [JsonPropertyName("source")] + public required CatalogCandidateSource Source { get; set; } + + /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("trust")] + public CatalogTrustSnapshot? Trust { get; set; } } -/// Session ID to delete from disk. +/// Where and when an AI skill catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsDeleteRequest +public sealed class CatalogAiSkillCandidateProvenance { - /// Session ID to delete. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. + [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("authority")] + public string Authority { get; set; } = string.Empty; - /// Internal resolved session directory path to delete. - [JsonPropertyName("sessionPath")] - public string? SessionPath { get; set; } + /// Media type advertised for the referenced AI skill card. + [JsonPropertyName("mediaType")] + public CatalogAiSkillMediaType MediaType { get; set; } + + /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. + [JsonPropertyName("observedAt")] + public string ObservedAt { get; set; } = string.Empty; } -/// Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. +/// An inert AI skill catalog result. Verified Skill candidates may be installable only when the runtime reports installability and the selected session is permitted to plan installation. +/// The ai-skill variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPruneResult +public partial class CatalogCandidateAiSkill : CatalogCandidate { - /// Session IDs that would be deleted in dry-run mode (always empty otherwise). - [JsonPropertyName("candidates")] - public IList Candidates { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "ai-skill"; - /// Session IDs that were deleted (always empty in dry-run mode). - [JsonPropertyName("deleted")] - public IList Deleted { get => field ??= []; set; } + /// Description taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// True when no deletions were actually performed. - [JsonPropertyName("dryRun")] - public bool DryRun { get; set; } + /// Display name taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } - /// Total bytes freed (actual when not dry-run, projected when dry-run). - [JsonPropertyName("freedBytes")] - public long FreedBytes { get; set; } + /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. + [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("handle")] + public required string Handle { get; set; } - /// Session IDs that were skipped (e.g., named sessions). - [JsonPropertyName("skipped")] - public IList Skipped { get => field ??= []; set; } -} + /// ISO 8601 timestamp after which the handle is stale and will be rejected. + [JsonPropertyName("handleExpiresAt")] + public required string HandleExpiresAt { get; set; } -/// Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsPruneOldRequest -{ - /// When true, only report what would be deleted without performing any deletion. - [JsonPropertyName("dryRun")] - public bool? DryRun { get; set; } + /// Whether this AI skill candidate can be planned for verified installation in the selected session. + [JsonPropertyName("installability")] + public required CatalogAiSkillInstallability Installability { get; set; } - /// Session IDs that should never be considered for pruning. - [JsonPropertyName("excludeSessionIds")] - public IList? ExcludeSessionIds { get; set; } + /// Media type of the underlying AI skill card. + [JsonPropertyName("mediaType")] + public required CatalogAiSkillMediaType MediaType { get; set; } - /// When true, named sessions (set via /rename) are also eligible for pruning. - [JsonPropertyName("includeNamed")] - public bool? IncludeNamed { get; set; } + /// Where the catalog reference was observed, without the card itself or any content digest. + [JsonPropertyName("provenance")] + public required CatalogAiSkillCandidateProvenance Provenance { get; set; } - /// Delete sessions whose modifiedTime is at least this many days old. - [JsonPropertyName("olderThanDays")] - public long OlderThanDays { get; set; } -} + /// Publisher taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("publisher")] + public string? Publisher { get; set; } -/// Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsSaveResult -{ -} + /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. + [JsonPropertyName("source")] + public required CatalogCandidateSource Source { get; set; } -/// Session ID whose pending events should be flushed to disk. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsSaveRequest -{ - /// Session ID whose pending events should be flushed to disk. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("trust")] + public CatalogTrustSnapshot? Trust { get; set; } } -/// 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. +/// Where and when an Agent Plugin catalog reference was observed. Discovery provenance deliberately carries no descriptor URL, raw data, candidate handle, or content digest. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsReleaseLockResult +public sealed class CatalogAgentPluginCandidateProvenance { -} + /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. + [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("authority")] + public string Authority { get; set; } = string.Empty; -/// Session ID whose in-use lock should be released. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsReleaseLockRequest -{ - /// Session ID whose in-use lock should be released. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Canonical Agent Plugin media type. + [JsonPropertyName("mediaType")] + public CatalogAgentPluginMediaType MediaType { get; set; } + + /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. + [JsonPropertyName("observedAt")] + public string ObservedAt { get; set; } = string.Empty; } -/// The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. +/// Syntactically validated GitHub repository provenance declared by catalog metadata. This is a source claim rather than proof that the descriptor URL resolves to the repository. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionEnrichMetadataResult +public sealed class CatalogPluginRepositorySource { - /// Enriched records, with summary and context backfilled. Sessions confirmed empty and unnamed may be omitted. - [JsonPropertyName("sessions")] - public IList Sessions { get => field ??= []; set; } + /// Case-preserving safe relative POSIX path derived from metadata.repoPath. + [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)] + [MaxLength(256)] + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Canonical lowercase owner/repository name derived from metadata.sourceSet. + [RegularExpression("^[a-z0-9_.-]+/[a-z0-9_.-]+$")] + [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(3)] + [MaxLength(256)] + [JsonPropertyName("repository")] + public string Repository { get; set; } = string.Empty; } -/// Session metadata records to enrich with summary and context information. +/// An inert Agent Plugin catalog result. Its canonical catalog identity, declared version, repository source claim, and explicit compatibility tags are safe to correlate, while its descriptor, URL, raw data, and installed-plugin state remain runtime-private. This contract-only variant does not mint or expose a candidate handle. +/// The plugin variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsEnrichMetadataRequest +public partial class CatalogCandidatePlugin : CatalogCandidate { - /// Session metadata records to enrich. Records that already have summary and context are returned unchanged. - [JsonPropertyName("sessions")] - public IList Sessions { get => field ??= []; set; } -} + /// + [JsonIgnore] + public override string Kind => "plugin"; -/// 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. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsReloadPluginHooksResult -{ -} + /// Explicit validated compatibility tags, in canonical order. An empty list means the source declared no recognised compatibility; clients must not infer compatibility from other fields. `canvas-only` requires both `canvas` and `github-copilot`. + [JsonPropertyName("compatibilityTags")] + public required IList CompatibilityTags { get; set; } -/// Active session ID and an optional flag for deferring repo-level hooks until folder trust. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsReloadPluginHooksRequest -{ - /// When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. - [JsonPropertyName("deferRepoHooks")] - public bool? DeferRepoHooks { get; set; } + /// Description taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Active session ID to reload hooks for. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Display name taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } -/// Queued repo-level startup prompts and the total hook command count after loading. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLoadDeferredRepoHooksResult -{ - /// Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. - [JsonPropertyName("hookCount")] - public long HookCount { get; set; } + /// Validated, normalised catalogue resource URN. This identity comes only from the catalog identifier and is never inferred from display text or installed-plugin state. + [JsonPropertyName("identity")] + public required string Identity { get; set; } - /// Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. - [JsonPropertyName("startupPrompts")] - public IList StartupPrompts { get => field ??= []; set; } -} + /// Canonical Agent Plugin media type. + [JsonPropertyName("mediaType")] + public required CatalogAgentPluginMediaType MediaType { get; set; } -/// Active session ID whose deferred repo-level hooks should be loaded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsLoadDeferredRepoHooksRequest -{ - /// Active session ID whose deferred repo-level hooks should be loaded. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Where the Agent Plugin catalog reference was observed, without its descriptor, URL, raw data, or content digest. + [JsonPropertyName("provenance")] + public required CatalogAgentPluginCandidateProvenance Provenance { get; set; } -/// 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. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsSetAdditionalPluginsResult -{ + /// Publisher taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("publisher")] + public string? Publisher { get; set; } + + /// Bounded repository provenance declared through the catalog's sourceSet and repoPath metadata. It contains no descriptor URL. + [JsonPropertyName("source")] + public required CatalogPluginRepositorySource Source { get; set; } + + /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility and emitted only when the caller also requires the trust-snapshot capability. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("trust")] + public CatalogTrustSnapshot? Trust { get; set; } + + /// Optional version declared by the catalog source. Omitted rather than guessed when the source supplies no version. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Installed plugin record from global state, with marketplace, version, install time, enabled state, cache path, and source. +/// Authority-reported navigation metadata, returned only to callers requiring catalog-search-pagination and only when a supported token is present. Tokenless first-page and continuation responses omit this object; no counts are inferred from candidates. The opaque token may be retained for previous or numbered navigation even when hasNextPage is false. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstalledPlugin +public sealed class CatalogSearchPagination { - /// Path where the plugin is cached locally. - [JsonPropertyName("cache_path")] - public string? CachePath { get; set; } - - /// Whether the plugin is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// One-based page returned by the authority. + [JsonPropertyName("currentPage")] + public int CurrentPage { get; set; } - /// Installation timestamp. - [JsonPropertyName("installed_at")] - public string InstalledAt { get; set; } = string.Empty; + /// Whether the authority token advertises a valid next target within the navigation window. Not inferred from token presence, truncated, or currentPage being less than pageCount. + [JsonPropertyName("hasNextPage")] + public bool HasNextPage { get; set; } - /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. - [JsonPropertyName("installed_from")] - public string? InstalledFrom { get; set; } + /// Navigation window ceiling ceil(1000 / pageSize), not the number of existing pages. Legal targets must not exceed this ceiling or the token's signed pageCount. + [JsonPropertyName("maxPage")] + public int MaxPage { get; set; } - /// Marketplace the plugin came from (empty string for direct repo installs). - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; + /// Backend-reported page count, which may exceed maxPage. Present pagination metadata always describes a multi-page result; zero- and single-page responses omit pagination. Navigation targets must also be within the signed pageCount carried by the supplied token. + [JsonPropertyName("pageCount")] + public long PageCount { get; set; } - /// Plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Page size bound to the search, equal to the effective request limit. + [JsonPropertyName("pageSize")] + public int PageSize { get; set; } - /// Source for direct repo installs (when marketplace is empty). - [JsonPropertyName("source")] - public JsonElement? Source { get; set; } + /// Opaque pagination token. Session-bound search returns an expiring runtime-owned reference retaining the exact private authority token, original search and authority. Legacy unbound search returns the authority token unchanged, without a runtime-created expiry. Only the runtime unwraps tokens or changes targetPage; SDK consumers must not decode, modify or log them. + [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)] + [MaxLength(4096)] + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; - /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. - [JsonPropertyName("source_sha")] - public string? SourceSha { get; set; } + /// Backend-reported count for this response, not the number of returned candidates. Its relationship to the full query result set is unknown. + [JsonPropertyName("totalCount")] + public long TotalCount { get; set; } - /// Version installed (if available). - [JsonPropertyName("version")] - public string? Version { get; set; } + /// The relationship of totalCount to the complete query result set is unknown; neither exactness nor a lower-bound guarantee is implied. + [JsonPropertyName("totalCountRelation")] + public CatalogSearchTotalCountRelation TotalCountRelation { get; set; } } -/// Manager-wide additional plugins to register; replaces any previously-configured set. +/// A completed catalog search containing inert candidate summaries. MCP server and AI skill variants carry a single-use handle; the Agent Plugin variant is handleless. +/// The succeeded variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsSetAdditionalPluginsRequest +public partial class CatalogSearchResultSucceeded : CatalogSearchResult { - /// Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } -} + /// + [JsonIgnore] + public override string Kind => "succeeded"; -/// Dynamic-context board entry count, when available. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetBoardEntryCountResult -{ - /// Board entry count, when available. - [JsonPropertyName("count")] - public long? Count { get; set; } + /// Matching candidates, never more than the requested limit. All text is inert untrusted data. + [JsonPropertyName("candidates")] + public required IList Candidates { get; set; } + + /// Protocol version and capabilities the runtime honoured. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } + + /// Navigation metadata for callers explicitly requiring catalog-search-pagination. Omitted when the authority returns no token, including tokenless first-page and continuation responses. Counts are never substituted from candidates.length. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pagination")] + public CatalogSearchPagination? Pagination { get; set; } + + /// Pseudonymous identifier for this search, issued by the runtime or by the catalog authority it queried and never by the caller, so it cannot be forged or replayed to attribute an install to a search that never happened. Always present on a success, so a result set can be tied to the installs it leads to. It identifies a search rather than a person: it is derived from no user, account, device, or query data, and must never be joined with user identity to re-identify anyone. + [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)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } + + /// Legacy indication that the authority returned a page token. Preserved for compatibility; this is not a has-next-page indicator. Use pagination.hasNextPage when pagination metadata is present. + [JsonPropertyName("truncated")] + public required bool Truncated { get; set; } } -/// Session ID whose board entry count should be returned. +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetBoardEntryCountRequest +public partial class CatalogSearchResultNegotiationRefused : CatalogSearchResult { - /// Session ID whose board entry count should be returned. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; + + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } + + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } + + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } + + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } + + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// State of the runtime-managed remote-control singleton. -/// Polymorphic base type discriminated by state. +/// The request asked for a candidate kind this runtime does not serve. +/// The unsupported-kind variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "state", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(RemoteControlStatusOff), "off")] -[JsonDerivedType(typeof(RemoteControlStatusConnecting), "connecting")] -[JsonDerivedType(typeof(RemoteControlStatusActive), "active")] -[JsonDerivedType(typeof(RemoteControlStatusError), "error")] -public partial class RemoteControlStatus +public partial class CatalogSearchResultUnsupportedKind : CatalogSearchResult { - /// The type discriminator. - [JsonPropertyName("state")] - public virtual string State { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Kind => "unsupported-kind"; + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } -/// Remote control is not connected. -/// The off variant of . + /// The kinds from the request that are not supported. + [JsonPropertyName("requestedKinds")] + public required IList RequestedKinds { get; set; } + + /// Every candidate kind this runtime can serve. + [JsonPropertyName("supportedKinds")] + public required IList SupportedKinds { get; set; } +} + +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusOff : RemoteControlStatus +public partial class CatalogSearchResultInvalidRequest : CatalogSearchResult { /// [JsonIgnore] - public override string State => "off"; + public override string Kind => "invalid-request"; + + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } + + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Remote control is in the middle of initial setup. -/// The connecting variant of . +/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. +/// The authentication-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusConnecting : RemoteControlStatus +public partial class CatalogSearchResultAuthenticationRequired : CatalogSearchResult { /// [JsonIgnore] - public override string State => "connecting"; + public override string Kind => "authentication-required"; - /// Session id the connection is attaching to. - [JsonPropertyName("attachedSessionId")] - public required string AttachedSessionId { get; set; } + /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. + [JsonPropertyName("reason")] + public required CatalogAuthenticationRequiredReason Reason { get; set; } } -/// Remote control is connected to a local session. -/// The active variant of . +/// Registry or enterprise policy refused the operation. +/// The policy-rejected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusActive : RemoteControlStatus +public partial class CatalogSearchResultPolicyRejected : CatalogSearchResult { /// [JsonIgnore] - public override string State => "active"; - - /// Session id remote control is pointed at. - [JsonPropertyName("attachedSessionId")] - public required string AttachedSessionId { get; set; } - - /// True while a read-only/session-sync export is deferred, awaiting the first `user.message` before its MC session exists. Marked internal: this field is excluded from the public SDK surface and is populated only on the CLI in-process path. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("awaitingFirstMessage")] - internal bool? AwaitingFirstMessage { get; set; } + public override string Kind => "policy-rejected"; - /// MC frontend URL for this session, when known. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("frontendUrl")] - public string? FrontendUrl { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Whether the MC session may steer this session. - [JsonPropertyName("isSteerable")] - public required bool IsSteerable { get; set; } + /// Which authority produced the decision. + [JsonPropertyName("source")] + public required McpPlanPolicySource Source { get; set; } } -/// The last setup attempt failed. The singleton is otherwise off. -/// The error variant of . +/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. +/// The network-failure variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusError : RemoteControlStatus +public partial class CatalogSearchResultNetworkFailure : CatalogSearchResult { /// [JsonIgnore] - public override string State => "error"; + public override string Kind => "network-failure"; - /// Session id the failing setup attempt targeted, when known. + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. + [JsonPropertyName("reason")] + public required CatalogNetworkFailureReason Reason { get; set; } + + /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("attachedSessionId")] - public string? AttachedSessionId { get; set; } + [JsonPropertyName("retryAfterSeconds")] + public int? RetryAfterSeconds { get; set; } - /// Human-readable error message from the last setup attempt. - [JsonPropertyName("error")] - public required string Error { get; set; } + /// HTTP status code, when the failure was a rejected response. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("statusCode")] + public int? StatusCode { get; set; } } -/// Wrapper for the singleton's current status. +/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. +/// The unsafe-retrieval variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlStatusResult +public partial class CatalogSearchResultUnsafeRetrieval : CatalogSearchResult { - /// State of the runtime-managed remote-control singleton. - [JsonPropertyName("status")] - public RemoteControlStatus Status { get => field ??= new(); set; } -} + /// + [JsonIgnore] + public override string Kind => "unsafe-retrieval"; -/// Reattach to an existing MC session without creating a new one. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlConfigExistingMcSession -{ - /// Existing MC session ID to reattach to. - [JsonPropertyName("mcSessionId")] - public string McSessionId { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Existing MC task ID for the reattached session. - [JsonPropertyName("mcTaskId")] - public string McTaskId { get; set; } = string.Empty; + /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. + [JsonPropertyName("reason")] + public required CatalogUnsafeRetrievalReason Reason { get; set; } } -/// Configuration for the runtime-managed remote-control singleton. +/// A card could not be parsed or did not satisfy its declared media type's schema. +/// The malformed-card variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlConfig +public partial class CatalogSearchResultMalformedCard : CatalogSearchResult { - /// Reattach to an existing MC session without creating a new one. - [JsonPropertyName("existingMcSession")] - public RemoteControlConfigExistingMcSession? ExistingMcSession { get; set; } - - /// Whether the user explicitly requested remote (vs. implicit session-sync). Controls warning surfacing for missing-repo cases. - [JsonPropertyName("explicit")] - public bool Explicit { get; set; } - - /// Whether remote export should be enabled. - [JsonPropertyName("remote")] - public bool Remote { get; set; } + /// + [JsonIgnore] + public override string Kind => "malformed-card"; - /// When true, suppresses timeline messages on successful setup. - [JsonPropertyName("silent")] - public bool Silent { get; set; } + /// Media type the card was interpreted as, when it declared one this runtime recognises. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mediaType")] + public CatalogMediaType? MediaType { get; set; } - /// Whether the MC session may steer the local session (write mode). - [JsonPropertyName("steerable")] - public bool Steerable { get; set; } + /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Existing Mission Control task ID to attach the exported session to. - [JsonPropertyName("taskId")] - public string? TaskId { get; set; } + /// How the card failed validation. + [JsonPropertyName("reason")] + public required CatalogMalformedCardReason Reason { get; set; } } -/// Parameters for attaching the remote-control singleton to a session. +/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. +/// The contract-violation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsStartRemoteControlRequest +public partial class CatalogSearchResultContractViolation : CatalogSearchResult { - /// Configuration for the runtime-managed remote-control singleton. - [JsonPropertyName("config")] - public RemoteControlConfig Config { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "contract-violation"; - /// Local session id to attach remote control to. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Which rule the response broke. + [JsonPropertyName("reason")] + public required CatalogContractViolationReason Reason { get; set; } } -/// Outcome of a transferRemoteControl call. +/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlTransferResult +public partial class CatalogSearchResultUnavailable : CatalogSearchResult { - /// State of the runtime-managed remote-control singleton. - [JsonPropertyName("status")] - public RemoteControlStatus Status { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "unavailable"; - /// Whether the rebinding actually happened. - [JsonPropertyName("transferred")] - public bool Transferred { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why the operation is unavailable. + [JsonPropertyName("reason")] + public required CatalogUnavailableReason Reason { get; set; } } -/// Parameters for atomically rebinding the remote-control singleton. +/// An explicit numbered-page request. SDK consumers treat the token as opaque. For bound search, the runtime unwraps an expiring owner-bound reference to the private authority token; only the runtime changes the authority token's targetPage. Legacy unbound navigation keeps its authority-issued token semantics. No snapshot stability is promised. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsTransferRemoteControlRequest +public sealed class CatalogSearchPage { - /// When provided, the transfer is rejected unless the singleton currently points at this session id (compare-and-swap semantics to avoid clobbering newer state). - [JsonPropertyName("expectedFromSessionId")] - public string? ExpectedFromSessionId { get; set; } + /// Requested one-based page. Must not exceed either the token's signed pageCount or the navigation window ceil(1000 / pageSize). Repeat the search without page to discover newly available pages beyond that signed pageCount. + [JsonPropertyName("number")] + public int Number { get; set; } - /// Local session id to point remote control at. - [JsonPropertyName("toSessionId")] - public string ToSessionId { get; set; } = string.Empty; + /// Opaque pagination token from an earlier response, owner-bound when session-bound search was requested. Never decode, modify or log it in an SDK consumer. Expired or foreign bound references require a fresh bound search, not a legacy retry. + [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)] + [MaxLength(4096)] + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// Patch for the singleton's steering state. +/// A bounded catalog search. Both the query length and the result count are capped by the schema so a caller cannot request an unbounded scan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsSetRemoteControlSteeringRequest +public sealed class CatalogSearchRequest { - /// Target steering state. Today only `true` is actionable on the underlying exporter; `false` is reserved for future use. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } -} + /// Protocol version and capabilities the caller requires. + [JsonPropertyName("contract")] + public required CatalogClientContract Contract { get; set; } -/// Outcome of a stopRemoteControl call. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlStopResult -{ - /// State of the runtime-managed remote-control singleton. - [JsonPropertyName("status")] - public RemoteControlStatus Status { get => field ??= new(); set; } + /// Restrict results to these candidate kinds. Agent Plugins are opt-in and require the `agent-plugin-discovery` capability so protocol-v3 clients generated before that variant cannot receive an unknown result; when omitted, the backwards-compatible MCP server and AI skill kinds are searched. + [JsonPropertyName("kinds")] + public IList? Kinds { get; set; } - /// Whether the singleton was actually torn down by this call. - [JsonPropertyName("stopped")] - public bool Stopped { get; set; } -} + /// Maximum number of candidates to return. Defaults to 10 when omitted. + [JsonPropertyName("limit")] + public int? Limit { get; set; } -/// RPC data type for SessionsStopRemoteControl operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsStopRemoteControlRequest -{ - /// When provided, the stop is rejected unless the singleton currently points at this session id (compare-and-swap semantics). - [JsonPropertyName("expectedSessionId")] - public string? ExpectedSessionId { get; set; } + /// Numbered navigation using metadata from an earlier response. Requires catalog-search-pagination and the same query, kinds and effective limit. Omit for a fresh first-page search. + [JsonPropertyName("page")] + public CatalogSearchPage? Page { get; set; } - /// When true, the singleton is unconditionally torn down regardless of `expectedSessionId`. Use during shutdown or explicit `/remote off`. - [JsonPropertyName("force")] - public bool? Force { get; set; } -} + /// + /// Select an existing attached local session. Requires authenticated, session-bound search. + /// The runtime never creates, resumes or reconfigures a session to honour this selector. + /// + [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)] + [MaxLength(256)] + [JsonPropertyName("policySessionId")] + public string? PolicySessionId { get; set; } -/// Params to attach or detach an in-process ExtensionController delegate. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConfigureSessionExtensionsParams -{ - /// Session to attach the extension controller delegate to. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Free-text search query. Persisted as tool input for session continuity, but omitted from telemetry. + [RegularExpression("\\S")] + [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)] + [MaxLength(256)] + [JsonPropertyName("query")] + public required string Query { get; set; } } -/// Outcome of an agentRegistry.spawn call. +/// Typed outcome of catalog.select. Only the selected host result carries a fresh candidate handle; the model-facing projection removes both that handle and searchId. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawned), "spawned")] -[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawnError), "spawn-error")] -[JsonDerivedType(typeof(AgentRegistrySpawnResultRegistryTimeout), "registry-timeout")] -[JsonDerivedType(typeof(AgentRegistrySpawnResultValidationError), "validation-error")] -public partial class AgentRegistrySpawnResult +[JsonDerivedType(typeof(CatalogSelectionResultSelected), "selected")] +[JsonDerivedType(typeof(CatalogSelectionResultDeclined), "declined")] +[JsonDerivedType(typeof(CatalogSelectionResultCancelled), "cancelled")] +[JsonDerivedType(typeof(CatalogSelectionResultTimedOut), "timed-out")] +[JsonDerivedType(typeof(CatalogSelectionResultInvalid), "invalid")] +[JsonDerivedType(typeof(CatalogSelectionResultStale), "stale")] +[JsonDerivedType(typeof(CatalogSelectionResultReplayed), "replayed")] +[JsonDerivedType(typeof(CatalogSelectionResultForeign), "foreign")] +[JsonDerivedType(typeof(CatalogSelectionResultWrongKind), "wrong-kind")] +[JsonDerivedType(typeof(CatalogSelectionResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(CatalogSelectionResultInvalidRequest), "invalid-request")] +[JsonDerivedType(typeof(CatalogSelectionResultUnavailable), "unavailable")] +public partial class CatalogSelectionResult { /// The type discriminator. [JsonPropertyName("kind")] @@ -8665,6244 +8624,5618 @@ public partial class AgentRegistrySpawnResult } -/// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). +/// The chosen candidate was transferred into a fresh bounded single-use handle for a later explicit planning request. +/// The selected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentRegistryLiveTargetEntry +public partial class CatalogSelectionResultSelected : CatalogSelectionResult { - /// Kind of attention required when status === "attention". Meaningful only when status === "attention". - [JsonPropertyName("attentionKind")] - public AgentRegistryLiveTargetEntryAttentionKind? AttentionKind { get; set; } - - /// Git branch of the session (when known). - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Copilot CLI version that wrote the entry. - [JsonPropertyName("copilotVersion")] - public string CopilotVersion { get; set; } = string.Empty; - - /// Working directory of the session (when known). - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } - - /// Bind host for the entry's JSON-RPC server. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// Process kind tag for the registry entry. - [JsonPropertyName("kind")] - public AgentRegistryLiveTargetEntryKind Kind { get; set; } - - /// Wall-clock milliseconds since the watcher last observed this entry (heartbeat freshness). - [JsonPropertyName("lastSeenMs")] - public long LastSeenMs { get; set; } - - /// How the most recent turn ended (clean vs aborted). Lets the renderer distinguish done from done_cancelled. - [JsonPropertyName("lastTerminalEvent")] - public AgentRegistryLiveTargetEntryLastTerminalEvent? LastTerminalEvent { get; set; } - - /// Model identifier currently selected for the session. - [JsonPropertyName("model")] - public string? Model { get; set; } - - /// Operating-system pid of the process owning this entry. - [JsonPropertyName("pid")] - public long Pid { get; set; } - - /// TCP port the entry's JSON-RPC server is listening on. - [JsonPropertyName("port")] - public long Port { get; set; } - - /// Registry entry schema version (1 = ui-server, 2 = managed-server). - [JsonPropertyName("schemaVersion")] - public long SchemaVersion { get; set; } + /// + [JsonIgnore] + public override string Kind => "selected"; - /// Session ID of the foreground session for this entry. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// Fresh single-use candidate handle accepted by mcp.planInstall. Returned only to the native host and never included in model-tool output. + [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)] + [MaxLength(256)] + [JsonPropertyName("candidateHandle")] + public required string CandidateHandle { get; set; } - /// Friendly session name (when set). - [JsonPropertyName("sessionName")] - public string? SessionName { get; set; } + /// The exact search identifier privately bound to the selected candidate. + [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)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } +} - /// ISO 8601 timestamp captured at registration. - [JsonPropertyName("startedAt")] - public string StartedAt { get; set; } = string.Empty; +/// The caller explicitly declined every candidate and the retained search state was released. +/// The declined variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class CatalogSelectionResultDeclined : CatalogSelectionResult +{ + /// + [JsonIgnore] + public override string Kind => "declined"; - /// Coarse lifecycle status of the foreground session. - [JsonPropertyName("status")] - public AgentRegistryLiveTargetEntryStatus? Status { get; set; } + /// The search identifier privately bound to the released selection group. + [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)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } +} - /// Monotonic per-publisher revision counter incremented on every status update. Lets watchers detect transient flips. - [JsonPropertyName("statusRevision")] - public long? StatusRevision { get; set; } +/// The caller cancelled the selection interaction and the retained search state was released. +/// The cancelled variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class CatalogSelectionResultCancelled : CatalogSelectionResult +{ + /// + [JsonIgnore] + public override string Kind => "cancelled"; - /// Connection token (null when the target is unauthenticated). - [JsonInclude] - [JsonPropertyName("token")] - internal string? Token { get; set; } + /// The search identifier privately bound to the released selection group. + [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)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } } -/// Canonical process-log discovery outcome; populated from spawnLiveTarget. +/// The host declared that its live selection interaction timed out, and the retained search state was released. +/// The timed-out variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentRegistryLogCapture +public partial class CatalogSelectionResultTimedOut : CatalogSelectionResult { - /// Whether a canonical process log was discovered for this managed spawn. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// + [JsonIgnore] + public override string Kind => "timed-out"; - /// Why no canonical process log could be opened for this managed spawn (set only when enabled is false). - [JsonPropertyName("openError")] - public string? OpenError { get; set; } + /// The search identifier privately bound to the released selection group. + [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)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } +} - /// Categorized reason no canonical process log could be opened (set only when enabled is false). - [JsonPropertyName("openErrorReason")] - public AgentRegistryLogCaptureOpenErrorReason? OpenErrorReason { get; set; } +/// The selection reference was malformed or unknown. +/// The invalid variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class CatalogSelectionResultInvalid : CatalogSelectionResult +{ + /// + [JsonIgnore] + public override string Kind => "invalid"; - /// Absolute path to the managed spawn's process-<timestamp>-<pid>.log file (only set when enabled). - [JsonPropertyName("path")] - public string? Path { get; set; } + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Managed-server child was spawned and registered successfully. -/// The spawned variant of . +/// The runtime-enforced selection reference lifetime elapsed before the request arrived. +/// The stale variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultSpawned : AgentRegistrySpawnResult +public partial class CatalogSelectionResultStale : CatalogSelectionResult { /// [JsonIgnore] - public override string Kind => "spawned"; - - /// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). - [JsonPropertyName("entry")] - public required AgentRegistryLiveTargetEntry Entry { get; set; } + public override string Kind => "stale"; - /// If the delegate attempted to send the initial prompt and failed, the categorized error message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("initialPromptError")] - public string? InitialPromptError { get; set; } + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } +} - /// Whether the delegate already sent the initial prompt. Always omitted in the current wiring: the controller sends the prompt post-attach via the standard LocalRpcSession.send path. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("initialPromptSent")] - public bool? InitialPromptSent { get; set; } +/// The selection group was already terminated or its pending host hand-off was already claimed. +/// The replayed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class CatalogSelectionResultReplayed : CatalogSelectionResult +{ + /// + [JsonIgnore] + public override string Kind => "replayed"; - /// Per-spawn log-capture outcome; populated from spawnLiveTarget. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("logCapture")] - public AgentRegistryLogCapture? LogCapture { get; set; } + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// `child_process.spawn` itself failed before the child entered the registry. -/// The spawn-error variant of . +/// The selection reference belongs to another runtime instance or session. +/// The foreign variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultSpawnError : AgentRegistrySpawnResult +public partial class CatalogSelectionResultForeign : CatalogSelectionResult { /// [JsonIgnore] - public override string Kind => "spawn-error"; - - /// Underlying errno code (e.g. ENOENT, EACCES) when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("code")] - public string? Code { get; set; } + public override string Kind => "foreign"; - /// Human-readable error message. + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] [JsonPropertyName("message")] public required string Message { get; set; } } -/// Spawn succeeded but the child did not publish a matching managed-server entry within the timeout. -/// The registry-timeout variant of . +/// The presented opaque handle was issued for another catalog operation. +/// The wrong-kind variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultRegistryTimeout : AgentRegistrySpawnResult +public partial class CatalogSelectionResultWrongKind : CatalogSelectionResult { /// [JsonIgnore] - public override string Kind => "registry-timeout"; - - /// Process ID of the orphaned child (so the caller can offer 'kill the pid' guidance). - [JsonPropertyName("childPid")] - public required long ChildPid { get; set; } + public override string Kind => "wrong-kind"; - /// Per-spawn log-capture outcome; populated from spawnLiveTarget. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("logCapture")] - public AgentRegistryLogCapture? LogCapture { get; set; } + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Synchronous pre-validation rejected the spawn request. -/// The validation-error variant of . +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultValidationError : AgentRegistrySpawnResult +public partial class CatalogSelectionResultNegotiationRefused : CatalogSelectionResult { /// [JsonIgnore] - public override string Kind => "validation-error"; - - /// Which parameter field was invalid. Omitted when the rejection is not field-specific. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("field")] - public AgentRegistrySpawnValidationErrorField? Field { get; set; } + public override string Kind => "negotiation-refused"; - /// Human-readable explanation; safe to surface in the UI banner. Never logged to unrestricted telemetry. + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] [JsonPropertyName("message")] public required string Message { get; set; } - /// Categorized reason for the rejection. Low-cardinality enum so telemetry can aggregate by reason without leaking raw paths or agent/model names. + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } + + /// Whether the version or the capability set was the problem. [JsonPropertyName("reason")] - public required AgentRegistrySpawnValidationErrorReason Reason { get; set; } + public required CatalogNegotiationRefusedReason Reason { get; set; } + + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } + + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } + + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// Inputs to spawn a managed-server child via the controller's spawn delegate. +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentRegistrySpawnRequest +public partial class CatalogSelectionResultInvalidRequest : CatalogSelectionResult { - /// Custom or built-in agent name (e.g. 'explore'). When omitted, the child uses its own default. - [JsonPropertyName("agentName")] - public string? AgentName { get; set; } + /// + [JsonIgnore] + public override string Kind => "invalid-request"; - /// Working directory for the spawned child (must be an existing directory). - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } - /// Optional first user message. Forwarded to the caller (the CLI's spawn wrapper sends it post-attach via the standard LocalRpcSession.send path). - [JsonPropertyName("initialPrompt")] - public string? InitialPrompt { get; set; } + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } +} - /// Model identifier to apply to the new session. - [JsonPropertyName("model")] - public string? Model { get; set; } +/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. +/// The unavailable variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class CatalogSelectionResultUnavailable : CatalogSelectionResult +{ + /// + [JsonIgnore] + public override string Kind => "unavailable"; - /// Friendly session name. Must satisfy validateSessionName: non-empty, no leading/trailing whitespace, <=100 chars, no control chars, no double quotes. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Permission posture for the new session. 'yolo' requires the controller-local session to currently be in allow-all mode. - [JsonPropertyName("permissionMode")] - public AgentRegistrySpawnPermissionMode? PermissionMode { get; set; } + /// Why the operation is unavailable. + [JsonPropertyName("reason")] + public required CatalogUnavailableReason Reason { get; set; } } -/// Identifies the target session. +/// Terminates one retained catalog selection group through an opaque reference previously returned by the model-safe search projection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSuspendRequest +internal sealed class CatalogSelectionRequest { - /// Target session identifier. + /// Protocol version and capabilities the caller requires. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } + + /// The terminal outcome declared by the caller. Timed-out means the host's live interaction deadline elapsed; a reference whose runtime TTL elapsed is rejected separately as stale. + [JsonPropertyName("outcome")] + public CatalogSelectionDecision Outcome { get; set; } + + /// Opaque runtime-instance scoped reference to one visible candidate. For a non-selected outcome, any candidate reference from the same search closes that search's retained group. + [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)] + [MaxLength(256)] + [JsonPropertyName("selectionRef")] + public string SelectionRef { get; set; } = string.Empty; + + /// Locally owned root session whose retained search state is being resolved. + [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)] + [MaxLength(256)] [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of sending a user message. +/// Information about an installed plugin tracked in global state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SendResult +public sealed class InstalledPluginInfo { - /// Unique identifier assigned to the message. - [JsonPropertyName("messageId")] - public string MessageId { get; set; } = string.Empty; -} + /// Opaque, stable hash identifying a direct (non-marketplace) install source. Present only for direct repo / URL / local installs; absent for marketplace plugins. Same source yields the same id; distinct sources never collide. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } -/// Provider-native structured output format. JSON Schema is forwarded without rewriting or validating the schema or the generated output. -/// Polymorphic base type discriminated by type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ResponseFormatJsonSchema), "json_schema")] -public partial class ResponseFormat -{ - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} + /// Whether the plugin is currently enabled for new sessions. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Whether the managed desired plugin currently has an installed or live record. Set to false for a managed desired entry retained in the listing after installation or reconciliation failed. + [JsonPropertyName("installed")] + public bool? Installed { get; set; } + /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — a plugin belonging to a directory/local marketplace, which is loaded from its real directory on every pass instead of a copy under the installed-plugins cache. Its presence is what marks a listed plugin as live: such a plugin is always present on disk, so `enabled` is its only meaningful state and it is never "not installed". + [JsonPropertyName("installedFrom")] + public string? InstalledFrom { get; set; } -/// A JSON Schema output contract. OpenAI receives the name, description, schema and strict setting; Anthropic receives the schema in output_config.format and always uses its native strict enforcement. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class JsonSchemaResponseFormat -{ - /// Optional description passed to OpenAI providers. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Whether enterprise managed settings control this plugin's enabled state. + [JsonPropertyName("managed")] + public bool? Managed { get; set; } - /// Name of the output schema, subject to the provider's naming restrictions. + /// The enabled state required by enterprise managed settings, when this plugin spec is managed. + [JsonPropertyName("managedDesiredEnabled")] + public bool? ManagedDesiredEnabled { get; set; } + + /// Marketplace the plugin came from. Empty string ("") for direct repo / URL / local installs. + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// JSON Schema passed unchanged to the inference provider. Schemas larger than 32 MiB when JSON-encoded are rejected before admission, using the runtime's existing request-size ceiling. This is not a guarantee that the entire model request fits. Supported keywords and schema restrictions are determined by the provider. - [JsonPropertyName("schema")] - public JsonElement Schema { get; set; } + /// Runtime-reported plugin provenance. Currently set to "builtin" only for plugins registered through the trusted host built-in boundary; absent for installed, marketplace, direct, and live plugins. + [JsonPropertyName("source")] + public string? Source { get; set; } - /// Optional strict enforcement setting for OpenAI providers. Omitted uses the provider default. Anthropic always enforces its supported schema subset. - [JsonPropertyName("strict")] - public bool? Strict { get; set; } + /// Installed version (when reported by the plugin manifest). + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// The json_schema variant of . +/// Plugins installed in user/global state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ResponseFormatJsonSchema : ResponseFormat +public sealed class PluginListResult { - /// - [JsonIgnore] - public override string Type => "json_schema"; - - /// JSON Schema and provider options for the turn's output. - [JsonPropertyName("jsonSchema")] - public required JsonSchemaResponseFormat JsonSchema { get; set; } + /// Installed plugins. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } } -/// Parameters for sending a user message to the session. +/// Result of installing a plugin. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendRequest +public sealed class PluginInstallResult { - /// The UI mode the agent was in when this message was sent. Defaults to the session's current mode. - [JsonPropertyName("agentMode")] - public SendAgentMode? AgentMode { get; set; } + /// Set when the install path is deprecated (e.g. direct repo / URL / local installs). Callers should surface this to end users. + [JsonPropertyName("deprecationWarning")] + public string? DeprecationWarning { get; set; } - /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } - - /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. - [JsonPropertyName("billable")] - public bool? Billable { get; set; } - - /// If provided, this is shown in the timeline instead of `prompt`. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } - - /// How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. - [JsonPropertyName("mode")] - public SendMode? Mode { get; set; } - - /// If true, adds the message to the front of the queue instead of the end. - [JsonPropertyName("prepend")] - public bool? Prepend { get; set; } - - /// The user message text. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; - - /// 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. - [JsonPropertyName("requestHeaders")] - public IDictionary? RequestHeaders { get; set; } - - /// 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. - [JsonPropertyName("requiredTool")] - public string? RequiredTool { get; set; } - - /// Provider-native output format for this turn, including all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. - [JsonPropertyName("responseFormat")] - public ResponseFormat? ResponseFormat { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - - /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. - [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] - [JsonInclude] - [JsonPropertyName("source")] - internal string? Source { get; set; } + /// The newly installed plugin's metadata. + [JsonPropertyName("plugin")] + public InstalledPluginInfo Plugin { get => field ??= new(); set; } - /// W3C Trace Context traceparent header for distributed tracing of this agent turn. - [JsonPropertyName("traceparent")] - public string? Traceparent { get; set; } + /// Optional post-install message provided by the plugin (e.g. setup instructions). + [JsonPropertyName("postInstallMessage")] + public string? PostInstallMessage { get; set; } - /// W3C Trace Context tracestate header for distributed tracing. - [JsonPropertyName("tracestate")] - public string? Tracestate { get; set; } + /// Number of skills discovered and installed from the plugin. + [JsonPropertyName("skillsInstalled")] + public long SkillsInstalled { get; set; } - /// If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } + /// Where the completed plugin tree was staged before atomic promotion. + [JsonPropertyName("stagingMode")] + public PluginInstallStagingMode? StagingMode { get; set; } } -/// Result of sending zero or more user messages. +/// Plugin source and optional working directory for relative-path resolution. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SendMessagesResult +internal sealed class PluginsInstallRequest { - /// Unique identifiers assigned to the messages, one per provided message in order. For a batch that starts a run, assistant messages use the final ID as originatingMessageId throughout that run, including tool iterations and stop-hook corrections. Immediate steering does not replace the active run's origin. Empty when no messages were provided; that run has no originatingMessageId. - [JsonPropertyName("messageIds")] - public IList MessageIds { get => field ??= []; set; } + /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; + + /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// A single user message to append to the session as part of a `session.sendMessages` turn. +/// Name (or spec) of the plugin to uninstall. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SendMessageItem +internal sealed class PluginsUninstallRequest { - /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with this message. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } - - /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. - [JsonInclude] - [JsonPropertyName("billable")] - internal bool? Billable { get; set; } - - /// If provided, this is shown in the timeline instead of `prompt`. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } - - /// The user message text. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; - - /// 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. - [JsonPropertyName("requiredTool")] - public string? RequiredTool { get; set; } + /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } - /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. - [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] - [JsonInclude] - [JsonPropertyName("source")] - internal string? Source { get; set; } + /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Parameters for sending zero or more user messages to the session in a single turn. Remote-backed (Mission Control) sessions do not support this method and will return an error. +/// Result of updating a single plugin. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendMessagesRequest +public sealed class PluginUpdateResult { - /// The UI mode the agent was in when these messages were sent. Defaults to the session's current mode. - [JsonPropertyName("agentMode")] - public SendAgentMode? AgentMode { get; set; } - - /// The user messages to append to the conversation, in order, before running one agent loop. When the batch starts a run, its final message is the primary initiating message; earlier messages provide context, not separate runs or replies. May be empty, in which case a single turn runs over the existing history with no new user message or originatingMessageId. - [JsonPropertyName("messages")] - public IList Messages { get => field ??= []; set; } - - /// How to deliver the messages. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. - [JsonPropertyName("mode")] - public SendMode? Mode { get; set; } - - /// If true, adds the messages to the front of the queue instead of the end. - [JsonPropertyName("prepend")] - public bool? Prepend { get; set; } - - /// 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. - [JsonPropertyName("requestHeaders")] - public IDictionary? RequestHeaders { get; set; } - - /// Provider-native output format for the whole turn, including an empty message batch and all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. - [JsonPropertyName("responseFormat")] - public ResponseFormat? ResponseFormat { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - - /// W3C Trace Context traceparent header for distributed tracing of this agent turn. - [JsonPropertyName("traceparent")] - public string? Traceparent { get; set; } + /// Version after the update, when reported by the plugin manifest. + [JsonPropertyName("newVersion")] + public string? NewVersion { get; set; } - /// W3C Trace Context tracestate header for distributed tracing. - [JsonPropertyName("tracestate")] - public string? Tracestate { get; set; } + /// Version that was previously installed, when available. + [JsonPropertyName("previousVersion")] + public string? PreviousVersion { get; set; } - /// If true, await completion of the agentic loop for this turn before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageIds`; the caller can rely on the agent having processed the messages before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } + /// Number of skills discovered and installed after the update. + [JsonPropertyName("skillsInstalled")] + public long SkillsInstalled { get; set; } } -/// Internal request for sending a system notification. +/// Name (or spec) of the plugin to update. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendSystemNotificationRequest +internal sealed class PluginsUpdateRequest { - /// Optional structured notification kind. - [JsonPropertyName("kind")] - public JsonElement? Kind { get; set; } - - /// Notification text to deliver to the model. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; - - /// Internal delivery options, including passive policy. - [JsonPropertyName("options")] - public JsonElement? Options { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Plugin name or "plugin@marketplace" spec to update. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Result of aborting the current turn. +/// Per-plugin result from updating all plugins, with versions, skills installed, success flag, and optional error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AbortResult +public sealed class PluginUpdateAllEntry { - /// Error message if the abort failed. + /// Error message (failure only). [JsonPropertyName("error")] public string? Error { get; set; } - /// Whether the abort completed successfully. + /// Marketplace the plugin came from. Empty string ("") for direct installs. + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name that was updated. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Version after the update, when available. + [JsonPropertyName("newVersion")] + public string? NewVersion { get; set; } + + /// Previously installed version, when available. + [JsonPropertyName("previousVersion")] + public string? PreviousVersion { get; set; } + + /// Number of skills installed after the update (success only). + [JsonPropertyName("skillsInstalled")] + public long? SkillsInstalled { get; set; } + + /// Whether the update succeeded for this plugin. [JsonPropertyName("success")] public bool Success { get; set; } } -/// Parameters for aborting the current turn. +/// Result of updating all installed plugins. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AbortRequest +public sealed class PluginUpdateAllResult { - /// Finite reason code describing why the current turn was aborted. - [JsonPropertyName("reason")] - public AbortReason? Reason { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Per-plugin update results in deterministic order. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } } -/// Result of interrupting the main agent turn. +/// Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InterruptMainTurnResult +internal sealed class PluginsEnableRequest { - /// Whether an in-flight main agent turn was interrupted. False when the main loop was not processing. - [JsonPropertyName("interrupted")] - public bool Interrupted { get; set; } + /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } + + /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Parameters for interrupting the main agent turn. +/// Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InterruptMainTurnRequest +internal sealed class PluginsDisableRequest { - /// When true, the user's queued prompts are preserved and run as the next turn once the interrupted turn unwinds; when false (the default), the queue is cleared like a plain abort. - [JsonPropertyName("flushQueued")] - public bool? FlushQueued { get; set; } + /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Identifies the target session. +/// Trusted built-in plugin directories to use for this runtime process. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCancelAllBackgroundAgentsRequest +internal sealed class PluginsBuiltinSetRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Complete replacement set of trusted built-in plugin directories. Every entry must be an absolute local filesystem path no longer than 4096 characters. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } } -/// Parameters for shutting down the session. +/// Registered marketplace summary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShutdownRequest +public sealed class MarketplaceInfo { - /// Dispatch deferred sessionEnd hooks in the background with their full per-hook timeoutSec instead of awaiting them under the short shared shutdown budget. Set this when the host process keeps running after the session closes (for example the CLI's /clear), so a slow hook neither blocks the close nor is aborted. Hooks still detached when the process later exits are terminated with it. Defaults to false. - [JsonPropertyName("detachSessionEndHooks")] - public bool? DetachSessionEndHooks { get; set; } + /// Whether the managed marketplace currently resolved into the runtime marketplace registry. Set to false when the desired managed entry is retained for governance visibility after loading or reconciliation failed. + [JsonPropertyName("available")] + public bool? Available { get; set; } - /// Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// True when this is a default marketplace shipped with the runtime. Defaults are not removable. + [JsonPropertyName("isDefault")] + public bool? IsDefault { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether enterprise managed settings provide and control this marketplace entry. + [JsonPropertyName("managed")] + public bool? Managed { get; set; } - /// Why the session is being shut down. Defaults to "routine" when omitted. - [JsonPropertyName("type")] - public ShutdownType? Type { get; set; } + /// Marketplace name (matches the @marketplace suffix in plugin specs). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Human-readable description of where the marketplace data is fetched from (e.g. "GitHub: owner/repo"). + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; } -/// Identifier of the session event that was emitted for the log message. +/// All registered marketplaces, including built-in defaults. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LogResult +public sealed class MarketplaceListResult { - /// The unique identifier of the emitted session event. - [JsonPropertyName("eventId")] - public Guid EventId { get; set; } + /// Registered marketplaces. + [JsonPropertyName("marketplaces")] + public IList Marketplaces { get => field ??= []; set; } } -/// Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. +/// Result of registering a new marketplace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LogRequest +public sealed class MarketplaceAddResult { - /// When true, the message is transient and not persisted to the session event log on disk. - [JsonPropertyName("ephemeral")] - public bool? Ephemeral { get; set; } - - /// Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". - [JsonPropertyName("level")] - public SessionLogLevel? Level { get; set; } - - /// Human-readable message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - - /// Optional actionable tip displayed alongside the message. Only honored on `level: "info"`. - [JsonPropertyName("tip")] - public string? Tip { get; set; } - - /// Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". - [JsonPropertyName("type")] - public string? Type { get; set; } - - /// Optional URL the user can open in their browser for more details. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("url")] - public string? Url { get; set; } + /// Final name of the marketplace as resolved from its manifest. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Adapter-declared policy that tells clients whether discovery may run automatically. +/// Marketplace source and optional working directory for relative-path resolution. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAutomaticDiscoveryPolicy +internal sealed class PluginsMarketplacesAddRequest { - /// Whether automatic discovery is allowed, limited to configured providers, or explicit-only. - [JsonPropertyName("mode")] - public ModelProviderAutomaticDiscoveryMode Mode { get; set; } + /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; - /// Maximum network scope used by this adapter during discovery. - [JsonPropertyName("networkScope")] - public ModelProviderDiscoveryNetworkScope NetworkScope { get; set; } + /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} - /// True when discovery requires non-null caller input. Omission or null is rejected before adapter execution. When false, omitted or null input selects adapter defaults without schema validation. - [JsonPropertyName("requiresInput")] - public bool RequiresInput { get; set; } +/// Outcome of the remove attempt, including dependent-plugin info when applicable. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MarketplaceRemoveResult +{ + /// Names of installed plugins that prevented removal. Populated only when `removed=false`. + [JsonPropertyName("dependentPlugins")] + public IList? DependentPlugins { get; set; } - /// True when the adapter must be enabled by a trusted owner, such as a trusted extension, before automatic discovery may run. - [JsonPropertyName("requiresTrust")] - public bool RequiresTrust { get; set; } + /// True when the marketplace was actually removed. False when removal was skipped because the marketplace has dependent plugins and `force` was not set. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } -/// An operation supported by a model-provider adapter. +/// Name of the marketplace to remove and an optional force flag. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAdapterOperationDescriptor +internal sealed class PluginsMarketplacesRemoveRequest { - /// Optional self-contained JSON Schema Draft 7 for non-null discovery input. Only supported on discover. No external references are resolved. Omitted or null input selects defaults when requiresInput is false. Without a schema, the adapter validates supplied input. - [JsonPropertyName("inputSchema")] - public JsonElement? InputSchema { get; set; } + /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. + [JsonPropertyName("force")] + public bool? Force { get; set; } - /// Supported operation name: `discover`, `getStatus`, or `models.list`. Unknown names and duplicate declarations are rejected. + /// Marketplace name to remove. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; } -/// Contributor attribution, independent of routing identity and authorization. +/// Plugin entry advertised by a marketplace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAttribution +public sealed class MarketplacePluginInfo { - /// Human-readable contributor name, not the adapter display name. - [JsonPropertyName("ownerDisplayName")] - public string? OwnerDisplayName { get; set; } - - /// Stable contributor identifier. Required and nonblank for extension and custom sources; optional for built-in and configured sources. Does not grant authority. - [JsonPropertyName("ownerId")] - public string? OwnerId { get; set; } + /// Short description from the marketplace catalog, when present. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Kind of component that supplied the adapter. Attribution does not confer authority. - [JsonPropertyName("source")] - public ModelProviderProvenanceSource Source { get; set; } + /// Plugin name as listed in the marketplace catalog. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// A normalized model-provider adapter in the session's effective catalog. +/// Plugins advertised by the marketplace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAdapterDescriptor +public sealed class MarketplaceBrowseResult { - /// Stable opaque identity for routing to this adapter. Unique in the effective catalog, independent of live registration generations. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; - - /// Adapter-declared policy for passive and automatic discovery. - [JsonPropertyName("automaticDiscovery")] - public ModelProviderAutomaticDiscoveryPolicy AutomaticDiscovery { get => field ??= new(); set; } + /// Plugins advertised by the marketplace. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } +} - /// Human-readable provider name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; +/// Name of the marketplace whose plugin catalog to fetch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesBrowseRequest +{ + /// Marketplace name to browse. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Operations supported by this provider adapter. - [JsonPropertyName("operations")] - public IList Operations { get => field ??= []; set; } +/// Per-marketplace refresh result, including marketplace name, success flag, and optional failure error. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MarketplaceRefreshEntry +{ + /// Error message (failure only). + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Attribution for the adapter itself. - [JsonPropertyName("provenance")] - public ModelProviderAttribution Provenance { get => field ??= new(); set; } + /// Marketplace name that was refreshed. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Descriptive provider family, such as `ollama`. Different adapters may have the same family; use adapterId for routing. - [JsonPropertyName("providerKind")] - public string ProviderKind { get; set; } = string.Empty; + /// Whether the refresh succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Normalized model-provider adapter definitions available to the session, not discovered instances. +/// Result of refreshing one or more marketplace catalogs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAdapterCatalog +public sealed class MarketplaceRefreshResult { - /// Available provider adapters ordered by adapterId. - [JsonPropertyName("providers")] - public IList Providers { get => field ??= []; set; } + /// Per-marketplace refresh results in deterministic order. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } } -/// Identifies the target session. +/// RPC data type for PluginsMarketplacesRefresh operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionProvidersGetCatalogRequest +internal sealed class PluginsMarketplacesRefreshRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + [JsonPropertyName("name")] + public string? Name { get; set; } } -/// Attribution for the adapter that produced a provider row. +/// Agent metadata, including identifiers, display details, source, tools, model, models, reasoning effort, MCP servers, skills, and file path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderProvenance +public sealed class AgentInfo { - /// Stable opaque adapter identity from the effective catalog. Treat this as a whole identifier, not a parseable owner or kind. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; + /// Description of the agent's purpose. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Human-readable contributor name, not the adapter display name. - [JsonPropertyName("ownerDisplayName")] - public string? OwnerDisplayName { get; set; } + /// Whether model-driven invocation is disabled for this agent. + [JsonPropertyName("disableModelInvocation")] + public bool? DisableModelInvocation { get; set; } - /// Stable contributor identifier when the adapter has an owner outside the runtime. Independent of the contribution mechanism and not a routing key. - [JsonPropertyName("ownerId")] - public string? OwnerId { get; set; } + /// Human-readable display name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Descriptive provider family that produced this row; not a routing key. - [JsonPropertyName("providerKind")] - public string ProviderKind { get; set; } = string.Empty; + /// Declarative hook actions keyed by event name, executed only while this agent is active. + [JsonPropertyName("hooks")] + public IDictionary>? Hooks { get; set; } - /// Kind of component that supplied the adapter. - [JsonPropertyName("source")] - public ModelProviderProvenanceSource Source { get; set; } -} + /// Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// Serializable reference to a discovered provider instance. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderInstanceReference -{ - /// Stable opaque identity of the adapter that owns this reference. Must be present in the target session's effective catalog. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; - - /// Stable instance identifier derived by the provider adapter, such as `ollama:{normalizedEndpoint}`. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("mcpServers")] + public IDictionary? McpServers { get; set; } - /// Absolute provider management URI. The adapter validates normalization, supported schemes, and permission to access it against its bound configuration; a reference does not grant authority. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("managementEndpoint")] - public string ManagementEndpoint { get; set; } = string.Empty; + /// Authored preferred model id for this agent. Runtime model selection may choose a different model; omitted means no authored preference. + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Descriptive provider family. Must match the selected adapter; not a routing key. - [JsonPropertyName("providerKind")] - public string ProviderKind { get; set; } = string.Empty; -} + /// Whether authored models are preferences or required constraints. + [JsonPropertyName("modelPolicy")] + public AgentModelPolicy? ModelPolicy { get; set; } -/// A normalized model-provider instance discovered by the runtime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderInstance -{ - /// Human-readable instance name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// Authored preferred model ids for this agent, in priority order. Runtime model selection chooses the first available model; omitted means no authored preference. + [JsonPropertyName("models")] + public IList? Models { get; set; } - /// Inference API endpoint when the provider exposes one separately from its management endpoint. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("inferenceEndpoint")] - public string? InferenceEndpoint { get; set; } + /// Name of the agent. Use `id` as the stable selection identifier. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Transport to use for inference against this instance. - [JsonPropertyName("inferenceTransport")] - public ProviderEndpointTransport? InferenceTransport { get; set; } + /// Absolute local file path of the agent definition. Only set for file-based agents loaded from disk; remote agents do not have a path. + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Provider family to use for inference against this instance. - [JsonPropertyName("inferenceType")] - public ProviderEndpointType? InferenceType { get; set; } + /// Authored base prompt for the agent. Runtime prompt assembly may add dynamic context at invocation time. Omitted from `session.agent.list` unless `includePrompt` is true. + [JsonPropertyName("prompt")] + public string? Prompt { get; set; } - /// Wire API to use for inference against this instance, when required by the provider family. - [JsonPropertyName("inferenceWireApi")] - public ProviderEndpointWireApi? InferenceWireApi { get; set; } + /// Authored reasoning effort for this agent. Applied on selection to models that support it; omitted means no authored preference. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Attribution for the adapter that produced this instance. - [JsonPropertyName("provenance")] - public ModelProviderProvenance Provenance { get => field ??= new(); set; } + /// Skill names preloaded into this agent's context. Omitted means none. + [JsonPropertyName("skills")] + public IList? Skills { get; set; } - /// Self-contained reference for subsequent provider operations. - [JsonPropertyName("reference")] - public ModelProviderInstanceReference Reference { get => field ??= new(); set; } -} + /// Where the agent definition was loaded from. + [JsonPropertyName("source")] + public AgentInfoSource? Source { get; set; } -/// Typed provider-operation outcome. Use the code for control flow and the optional message for display. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderOperationOutcome -{ - /// Machine-readable operation outcome. - [JsonPropertyName("code")] - public ModelProviderOperationOutcomeCode Code { get; set; } + /// Allowed tool names for this agent. Empty array means none; omitted means inherit defaults. + [JsonPropertyName("tools")] + public IList? Tools { get; set; } - /// Human-readable detail for non-success outcomes. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Whether the agent can be selected directly by the user. Agents marked `false` are subagent-only. + [JsonPropertyName("userInvocable")] + public bool? UserInvocable { get; set; } } -/// Provider instances found by a discovery operation. +/// Agents discovered across user, project, plugin, and remote sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderDiscoverResult +public sealed class ServerAgentList { - /// Discovered provider instances. Empty when passive default discovery finds no reachable provider. - [JsonPropertyName("instances")] - public IList Instances { get => field ??= []; set; } - - /// Typed operation outcome. Passive discovery can return `absent` with an empty instance list. - [JsonPropertyName("outcome")] - public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } + /// All discovered agents across all sources. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } } -/// Provider discovery parameters. +/// Optional project paths to include in agent discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderDiscoverRequest +public sealed class AgentsDiscoverRequest { - /// Opaque adapter identity returned by `session.providers.getCatalog`. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } - /// Provider-specific JSON input. Omission or null selects adapter defaults unless requiresInput is true. Non-null input is validated against the advertised Draft 7 schema when present; otherwise validation belongs to the adapter. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } + /// When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. + [JsonPropertyName("excludeHostAgents")] + public bool? ExcludeHostAgents { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } } -/// Current health information for a provider instance. +/// Canonical directory where custom agents can be discovered or created, with scope, preference, and optional project path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderStatus +public sealed class AgentDiscoveryPath { - /// Normalized provider instance. - [JsonPropertyName("instance")] - public ModelProviderInstance Instance { get => field ??= new(); set; } + /// Absolute path of the search/create directory (may not exist on disk yet). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Typed operation outcome. - [JsonPropertyName("outcome")] - public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } + /// Whether this is the canonical directory to create a new agent in its tier. At most one entry per tier is preferred. + [JsonPropertyName("preferredForCreation")] + public bool PreferredForCreation { get; set; } - /// Open provider status value, such as `healthy`, `unreachable`, or `notInstalled`. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; + /// The input project path this directory was derived from (only for project scope). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } - /// Provider-reported version. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Which tier this directory belongs to. + [JsonPropertyName("scope")] + public AgentDiscoveryPathScope Scope { get; set; } } -/// Provider status request parameters. +/// Canonical locations where custom agents can be created so the runtime will recognize them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderGetStatusRequest +public sealed class AgentDiscoveryPathList { - /// Provider instance reference returned by discovery. - [JsonPropertyName("instance")] - public ModelProviderInstanceReference Instance { get => field ??= new(); set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Canonical agent create/discovery directories, in priority order. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } } -/// Provider-reported model artifact metadata. +/// Optional project paths to include when enumerating agent discovery directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelArtifactDetails +public sealed class AgentsGetDiscoveryPathsRequest { - /// Provider-reported model architecture. - [JsonPropertyName("architecture")] - public string? Architecture { get; set; } - - /// Provider-reported model families. - [JsonPropertyName("families")] - public IList? Families { get; set; } + /// Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } - /// Primary model family. - [JsonPropertyName("family")] - public string? Family { get; set; } + /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). + [JsonPropertyName("excludeHostAgents")] + public bool? ExcludeHostAgents { get; set; } - /// Artifact format, such as `gguf`. - [JsonPropertyName("format")] - public string? Format { get; set; } + /// Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } +} - /// Provider-reported parameter count label. - [JsonPropertyName("parameterSize")] - public string? ParameterSize { get; set; } +/// The agents this runtime ships, named so a consumer can tell them apart from authored ones. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsGetBuiltinsResult +{ + /// The subset of `names` a user is allowed to turn off. A shipped agent outside this list is always active and a client should not offer a toggle for it. + [JsonPropertyName("disableableNames")] + public IList DisableableNames { get => field ??= []; set; } - /// Provider-reported quantization label. - [JsonPropertyName("quantization")] - public string? Quantization { get; set; } + /// Every agent name this runtime ships. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } - /// Provider-reported tokenizer. - [JsonPropertyName("tokenizer")] - public string? Tokenizer { get; set; } + /// The subset of `names` defined by a shipped YAML definition. The remainder are special-cased in code and have no definition to load. + [JsonPropertyName("yamlBasedNames")] + public IList YamlBasedNames { get => field ??= []; set; } } -/// A non-fatal provider observation warning. +/// A shipped agent, named and described. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderWarning +internal sealed class BuiltinAgentSummary { - /// Machine-readable warning code. - [JsonPropertyName("code")] - public string Code { get; set; } = string.Empty; + /// One-line description of what the agent does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Human-readable warning message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// The agent name, as it appears in `getBuiltins`. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// A model offered for agent conversations. Missing capability metadata does not disqualify a candidate. Models known to be incompatible, such as embedding-only models, are excluded by the adapter. +/// The shipped agents available under the requested flags. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredModel +internal sealed class AgentsGetAvailableBuiltinsResult { - /// Provider-reported model capabilities. Omitted capability fields are unknown; explicit false values are preserved. - [JsonPropertyName("capabilities")] - public ModelCapabilities Capabilities { get => field ??= new(); set; } - - /// Provider-reported model artifact details. - [JsonPropertyName("details")] - public ModelArtifactDetails Details { get => field ??= new(); set; } - - /// Provider-reported artifact digest. - [JsonPropertyName("digest")] - public string? Digest { get; set; } - - /// Provider-native model identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Provider-reported last-modified timestamp. - [JsonPropertyName("modifiedAt")] - public DateTimeOffset? ModifiedAt { get; set; } - - /// Provider-reported display name. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Available shipped agents, in the runtime's own order. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } +} - /// Attribution for the adapter that produced this model row. - [JsonPropertyName("provenance")] - public ModelProviderProvenance Provenance { get => field ??= new(); set; } +/// The feature flags to evaluate shipped agents against. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsGetAvailableBuiltinsRequest +{ + /// The surface asking, which gates agents that only apply to one client. Omit or pass null to apply no client filter. + [JsonPropertyName("context")] + public string? Context { get; set; } - /// Provider-reported artifact size in bytes. - [JsonPropertyName("sizeBytes")] - public long? SizeBytes { get; set; } + /// Feature flag values keyed by name, evaluated with the runtime's truthiness rules. Omit or pass null for no flags. + [JsonPropertyName("featureFlags")] + public IDictionary? FeatureFlags { get; set; } - /// Non-fatal warnings encountered while enriching this model. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// Flag overrides keyed by name. A null entry uses the corresponding base flag; false explicitly disables it. Omit or pass null for no overrides. + [JsonPropertyName("overrides")] + public IDictionary? Overrides { get; set; } } -/// Models offered for agent conversations by one provider instance. Adapters exclude known-incompatible models, but retain candidates with unknown capabilities. Listing does not guarantee compatibility. +/// One shipped agent's definition. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredModelList +internal sealed class AgentsGetBuiltinDefinitionResult { - /// Provider-native models in provider order. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } - - /// Typed operation outcome. - [JsonPropertyName("outcome")] - public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } + /// The agent's definition, serialized as JSON. It carries the authored keys plus the runtime's projected `__nativeCustomAgent` view of the same agent. It is a string rather than an object because the runtime parses it with the agent schema's tolerant shape, which accepts keys this contract does not name. + [JsonPropertyName("definitionJson")] + public string DefinitionJson { get; set; } = string.Empty; } -/// Provider model inventory request parameters. +/// The shipped agent whose definition to load. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderModelsListRequest +internal sealed class AgentsGetBuiltinDefinitionRequest { - /// Provider instance reference returned by discovery. - [JsonPropertyName("instance")] - public ModelProviderInstanceReference Instance { get => field ??= new(); set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The agent name, which must be one of `getBuiltins`'s `yamlBasedNames`. A name outside that list is special-cased in code and has no definition, and is reported as an error rather than as an empty definition. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Vision-specific limits. +/// One shipped agent, projected for a listing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverrideLimitsVision +internal sealed class AgentsGetBuiltinListingDefinitionResult { - /// Maximum image size in bytes. - [JsonPropertyName("max_prompt_image_size")] - public long? MaxPromptImageSize { get; set; } - - /// Maximum number of images per prompt. - [JsonPropertyName("max_prompt_images")] - public long? MaxPromptImages { get; set; } - - /// MIME types the model accepts. - [JsonPropertyName("supported_media_types")] - public IList? SupportedMediaTypes { get; set; } + /// The agent projected as a custom agent, serialized as JSON. It is a string rather than an object for the same reason as `getBuiltinDefinition`: the runtime parses the underlying definition with the agent schema's tolerant shape, which accepts keys this contract does not name. + [JsonPropertyName("definitionJson")] + public string DefinitionJson { get; set; } = string.Empty; } -/// Token limits for prompts, outputs, and context window. +/// The shipped agent whose listing entry to load. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverrideLimits +internal sealed class AgentsGetBuiltinListingDefinitionRequest { - /// Maximum total context window size in tokens. - [JsonPropertyName("max_context_window_tokens")] - public long? MaxContextWindowTokens { get; set; } - - /// Maximum number of output/completion tokens. - [JsonPropertyName("max_output_tokens")] - public long? MaxOutputTokens { get; set; } - - /// Maximum number of prompt/input tokens. - [JsonPropertyName("max_prompt_tokens")] - public long? MaxPromptTokens { get; set; } - - /// Vision-specific limits. - [JsonPropertyName("vision")] - public ModelCapabilitiesOverrideLimitsVision? Vision { get; set; } + /// The agent name, taken from `getAvailableBuiltins`. Unlike `getBuiltinDefinition`, the agent that `getBuiltins` reports as special-cased rather than YAML-based is answered here too, from its in-code definition. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Feature flags indicating what the model supports. +/// The model to switch to, and the warning to show when the agent's preference could not be met. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverrideSupports +internal sealed class AgentsCustomAgentInitialModelDecisionResult { - /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). - [JsonPropertyName("adaptive_thinking")] - public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } - - /// Whether this model supports reasoning effort configuration. + /// The reasoning effort attached to the selected model preference. Absent when that preference does not specify an effort. [JsonPropertyName("reasoningEffort")] - public bool? ReasoningEffort { get; set; } + public string? ReasoningEffort { get; set; } - /// Whether this model supports canonical tool calling. - [JsonPropertyName("toolCalls")] - public bool? ToolCalls { get; set; } + /// The first available model that matches the agent's preferences. Absent when none of the requested models is available. + [JsonPropertyName("targetModel")] + public string? TargetModel { get; set; } - /// Whether this model supports vision/image input. - [JsonPropertyName("vision")] - public bool? Vision { get; set; } + /// What to tell the user about an unmet preference. Absent when the preference was met. A warning with no `targetModel` means the agent's models are all unavailable. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Optional capability overrides (vision, tool_calls, reasoning, etc.). +/// The models a custom agent asks for, and the models actually available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverride +internal sealed class AgentsCustomAgentInitialModelDecisionParams { - /// Token limits for prompts, outputs, and context window. - [JsonPropertyName("limits")] - public ModelCapabilitiesOverrideLimits? Limits { get; set; } + /// The agent's declared `model:` entry, serialized. A single name or an ordered list of acceptable names. + [JsonPropertyName("agentModelsJson")] + public string AgentModelsJson { get; set; } = string.Empty; - /// Feature flags indicating what the model supports. - [JsonPropertyName("supports")] - public ModelCapabilitiesOverrideSupports? Supports { get; set; } + /// The models available to this session, serialized in the shape the model list carries. + [JsonPropertyName("availableModelsJson")] + public string AvailableModelsJson { get; set; } = string.Empty; } -/// RPC data type for ProtocolSystemMessageAppendConfig operations. +/// Installed plugin record from global state, with marketplace, version, install time, enabled state, cache path, and source. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolSystemMessageAppendConfig +public sealed class InstalledPlugin { - /// Text appended to the standard system prompt. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// Path where the plugin is cached locally. + [JsonPropertyName("cache_path")] + public string? CachePath { get; set; } - /// Append-mode discriminator. Omission also selects append mode. - [JsonPropertyName("mode")] - public ProtocolAppendMode? Mode { get; set; } -} + /// Whether the plugin is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } -/// RPC data type for SystemMessageBlock operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SystemMessageBlock -{ - /// Whether providers with explicit prompt caching should place a cache breakpoint after this block. - [JsonPropertyName("cacheBreakpoint")] - public bool? CacheBreakpoint { get; set; } + /// Installation timestamp. + [JsonPropertyName("installed_at")] + public string InstalledAt { get; set; } = string.Empty; - /// Text content for this system-message block. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. + [JsonPropertyName("installed_from")] + public string? InstalledFrom { get; set; } - /// Whether the block is static and may be cached independently of dynamic prompt content. - [JsonPropertyName("isStatic")] - public bool? IsStatic { get; set; } + /// Marketplace the plugin came from (empty string for direct repo installs). + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Source for direct repo installs (when marketplace is empty). + [JsonPropertyName("source")] + public JsonElement? Source { get; set; } + + /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. + [JsonPropertyName("source_sha")] + public string? SourceSha { get; set; } + + /// Version installed (if available). + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// RPC data type for ProtocolSystemMessageReplaceConfig operations. +/// An account the host has signed in to, identified by the server it lives on and the login it uses there. The same person can appear more than once when they use both github.com and an Enterprise server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolSystemMessageReplaceConfig +internal sealed class LoggedInUser { - /// Complete replacement system-message text. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Source account this account was derived from, when one was recorded. + [JsonPropertyName("derivedFrom")] + public string? DerivedFrom { get; set; } - /// Optional structured blocks corresponding to the replacement content. - [JsonPropertyName("contentBlocks")] - public IList? ContentBlocks { get; set; } + /// Host the account belongs to, such as `github.com` or an Enterprise server. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Replace-mode discriminator. - [JsonPropertyName("mode")] - public ProtocolReplaceMode Mode { get; set; } + /// Account kind, when the host recorded one. Consumers must tolerate new strings. + [JsonPropertyName("kind")] + public string? Kind { get; set; } + + /// Account login on that host. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; } -/// RPC data type for ProtocolStaticSectionOverride operations. +/// The host's machine-wide state. Every field is optional because a fresh install has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolStaticSectionOverride +internal sealed class GlobalStateLoadResult { - /// Declarative operation applied to the section. - [JsonPropertyName("action")] - public ProtocolStaticSectionAction Action { get; set; } + /// Whether the app tip has been shown. + [JsonPropertyName("appTipShown")] + public bool? AppTipShown { get; set; } - /// Optional content used by replace, append, and prepend operations. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// Terminals the user has already been asked to set up, so the host does not ask twice. + [JsonPropertyName("askedSetupTerminals")] + public IList? AskedSetupTerminals { get; set; } + + /// When the Auto-feedback hint was last shown, as an ISO 8601 timestamp. It enforces the once-per-day cap for non-staff users across restarts. + [JsonPropertyName("autoFeedbackLastPromptedAt")] + public string? AutoFeedbackLastPromptedAt { get; set; } + + /// When the host first ran on this machine. + [JsonPropertyName("firstLaunchAt")] + public string? FirstLaunchAt { get; set; } + + /// Plugins installed on this machine. + [JsonPropertyName("installedPlugins")] + public IList? InstalledPlugins { get; set; } + + /// Account used for the most recent sign-in. + [JsonPropertyName("lastLoggedInUser")] + public LoggedInUser? LastLoggedInUser { get; set; } + + /// Every account the host has signed in to on this machine. + [JsonPropertyName("loggedInUsers")] + public IList? LoggedInUsers { get; set; } + + /// Whether the one-off cleanup of stored reasoning summaries has run. + [JsonPropertyName("reasoningSummariesCleanupDone")] + public bool? ReasoningSummariesCleanupDone { get; set; } + + /// Models the user selected recently, most recent first. + [JsonPropertyName("recentModelIds")] + public IList? RecentModelIds { get; set; } + + /// Whether the user declined to trust the sandbox credential proxy CA. + [JsonPropertyName("sandboxCredentialProxyCaDeclined")] + public bool? SandboxCredentialProxyCaDeclined { get; set; } + + /// Whether the sandbox onboarding has been shown. + [JsonPropertyName("sandboxOnboardingShown")] + public bool? SandboxOnboardingShown { get; set; } + + /// Whether the user is a GitHub or Microsoft staff member, which unlocks internal-only behavior. + [JsonPropertyName("staff")] + public bool? Staff { get; set; } + + /// Whether the user was recognized as GitHub staff. + [JsonPropertyName("staffGithub")] + public bool? StaffGitHub { get; set; } + + /// When the staff-only log level migration last ran. + [JsonPropertyName("staffLogLevelMigrationAt")] + public string? StaffLogLevelMigrationAt { get; set; } + + /// Whether the user was recognized as Microsoft staff. + [JsonPropertyName("staffMicrosoft")] + public bool? StaffMicrosoft { get; set; } + + /// When the staff-only model reset last ran. + [JsonPropertyName("staffModelResetAt")] + public string? StaffModelResetAt { get; set; } + + /// When the staff-only update channel migration last ran. + [JsonPropertyName("staffUpdateChannelMigrationAt")] + public string? StaffUpdateChannelMigrationAt { get; set; } + + /// Folders where the user declined the init prompt, so it stays hidden there. + [JsonPropertyName("suppressInitFolders")] + public IList? SuppressInitFolders { get; set; } + + /// Folders the user has marked as trusted. + [JsonPropertyName("trustedFolders")] + public IList? TrustedFolders { get; set; } } -/// Polymorphic base type discriminated by action. +/// Selects the configuration directory whose machine-wide state to read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "action", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ProtocolMarkerSectionOverrideTransform), "transform")] -[JsonDerivedType(typeof(ProtocolMarkerSectionOverridePreserve), "preserve")] -public partial class ProtocolMarkerSectionOverride +internal sealed class GlobalStateLoadForConfigDirRequest { - /// The type discriminator. - [JsonPropertyName("action")] - public virtual string Action { get; set; } = string.Empty; + /// Copilot configuration directory to read the state document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } } - -/// The transform variant of . +/// A single top-level key to record in the host's machine-wide state. The write replaces only that key and leaves the rest of the document untouched, so two writers recording different one-off flags do not overwrite each other. The stored credential keys cannot be written through this method. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ProtocolMarkerSectionOverrideTransform : ProtocolMarkerSectionOverride +internal sealed class GlobalStateWriteKeyRequest { - /// - [JsonIgnore] - public override string Action => "transform"; + /// Copilot configuration directory to write the state document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to write the directory the server resolved for itself. Mirrors `globalState.loadForConfigDir`, so a caller can read and write the same directory. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } + + /// Top-level key to write, named as it appears in the result of `globalState.load`. It must be one of the writable keys that `globalState.writeKey` lists. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; + + /// Value to store for the key. Omit it, or pass null, to remove the key instead. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// The preserve variant of . +/// A literal choice the command input accepts, with a human-facing description. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ProtocolMarkerSectionOverridePreserve : ProtocolMarkerSectionOverride +public sealed class SlashCommandInputChoice { - /// - [JsonIgnore] - public override string Action => "preserve"; + /// Human-readable description shown alongside the choice. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// The literal choice value (e.g. 'on', 'off', 'show'). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// JSON union data type for ProtocolSectionOverride. +/// Optional unstructured input hint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -public sealed partial class ProtocolSectionOverride +public sealed class SlashCommandInput { - /// Gets the value when this instance contains . - public ProtocolStaticSectionOverride? ProtocolStaticSectionOverride { get; } + /// Optional literal choices the input accepts, each with a human-facing description; clients may render these as selectable options. + [JsonPropertyName("choices")] + public IList? Choices { get; set; } - /// Gets the value when this instance contains . - public ProtocolMarkerSectionOverride? ProtocolMarkerSectionOverride { get; } + /// Optional completion hint for the input (e.g. 'directory' for filesystem path completion). + [JsonPropertyName("completion")] + public SlashCommandInputCompletion? Completion { get; set; } - /// Initializes a new instance of the class from . - public ProtocolSectionOverride(ProtocolStaticSectionOverride value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolStaticSectionOverride = value; - } + /// Hint to display when command input has not been provided. + [JsonPropertyName("hint")] + public string Hint { get; set; } = string.Empty; - /// Converts to . - public static implicit operator ProtocolSectionOverride(ProtocolStaticSectionOverride value) => new(value); + /// When true, clients should pass the full text after the command name as a single argument rather than splitting on whitespace. + [JsonPropertyName("preserveMultilineInput")] + public bool? PreserveMultilineInput { get; set; } - /// Initializes a new instance of the class from . - public ProtocolSectionOverride(ProtocolMarkerSectionOverride value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolMarkerSectionOverride = value; - } + /// When true, the command requires non-empty input; clients should render the input hint as required. + [JsonPropertyName("required")] + public bool? Required { get; set; } +} - /// Converts to . - public static implicit operator ProtocolSectionOverride(ProtocolMarkerSectionOverride value) => new(value); +/// Slash-command metadata with name, aliases, description, kind, input hint, execution allowance, and schedulability. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SlashCommandInfo +{ + /// Canonical aliases without leading slashes. + [JsonPropertyName("aliases")] + public IList? Aliases { get; set; } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ProtocolSectionOverride Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) - { - throw new JsonException("Expected JSON object for ProtocolSectionOverride."); - } + /// Whether the command may run while an agent turn is active. + [JsonPropertyName("allowDuringAgentExecution")] + public bool AllowDuringAgentExecution { get; set; } - using var document = JsonDocument.ParseValue(ref reader); - var element = document.RootElement; - if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "replace" || element.GetProperty("action").GetString() == "remove" || element.GetProperty("action").GetString() == "append" || element.GetProperty("action").GetString() == "prepend"))) - { - var protocolStaticSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolStaticSectionOverride); - return protocolStaticSectionOverride is null ? throw new JsonException("Expected ProtocolStaticSectionOverride value.") : new ProtocolSectionOverride(protocolStaticSectionOverride); - } - if ((element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "transform")) || element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "preserve")))) - { - var protocolMarkerSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolMarkerSectionOverride); - return protocolMarkerSectionOverride is null ? throw new JsonException("Expected ProtocolMarkerSectionOverride value.") : new ProtocolSectionOverride(protocolMarkerSectionOverride); - } + /// Human-readable command description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - throw new JsonException("JSON value did not match any ProtocolSectionOverride variant."); - } + /// Whether the command is experimental. + [JsonPropertyName("experimental")] + public bool? Experimental { get; set; } - /// - public override void Write(Utf8JsonWriter writer, ProtocolSectionOverride value, JsonSerializerOptions options) - { - if (value.ProtocolStaticSectionOverride is { } protocolStaticSectionOverride) - { - JsonSerializer.Serialize(writer, protocolStaticSectionOverride, RpcJsonContext.Default.ProtocolStaticSectionOverride); - return; - } - if (value.ProtocolMarkerSectionOverride is { } protocolMarkerSectionOverride) - { - JsonSerializer.Serialize(writer, protocolMarkerSectionOverride, RpcJsonContext.Default.ProtocolMarkerSectionOverride); - return; - } + /// Optional unstructured input hint. + [JsonPropertyName("input")] + public SlashCommandInput? Input { get; set; } - throw new JsonException("No ProtocolSectionOverride variant value is set."); - } - } + /// Coarse command category for grouping and behavior: runtime built-in, skill-backed command, or SDK/client-owned command. + [JsonPropertyName("kind")] + public SlashCommandKind Kind { get; set; } + + /// Canonical command name without a leading slash. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Whether the command may be the target of `/every` / `/after` schedules. Resolution happens at every tick, so only set this when the command is safe to re-invoke and produces an agent prompt. + [JsonPropertyName("schedulable")] + public bool? Schedulable { get; set; } } -/// RPC data type for ProtocolSystemMessageCustomizeConfig operations. +/// Slash commands available in the session, after applying any include/exclude filters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolSystemMessageCustomizeConfig +public sealed class CommandList { - /// Text appended after the customized sections. - [JsonPropertyName("content")] - public string? Content { get; set; } - - /// Customize-mode discriminator. - [JsonPropertyName("mode")] - public ProtocolCustomizeMode Mode { get; set; } - - /// Named standard-prompt section overrides. - [JsonPropertyName("sections")] - public IDictionary? Sections { get; set; } + /// Commands available in this session. + [JsonPropertyName("commands")] + public IList Commands { get => field ??= []; set; } } -/// JSON union data type for ProtocolSystemMessageConfig. +/// Owner, name, and host of a GitHub repository, as resolved from a git remote URL. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -public sealed partial class ProtocolSystemMessageConfig +public sealed class GitHubRepositoryIdentity { - /// Gets the value when this instance contains . - public ProtocolSystemMessageAppendConfig? ProtocolSystemMessageAppendConfig { get; } - - /// Gets the value when this instance contains . - public ProtocolSystemMessageReplaceConfig? ProtocolSystemMessageReplaceConfig { get; } - - /// Gets the value when this instance contains . - public ProtocolSystemMessageCustomizeConfig? ProtocolSystemMessageCustomizeConfig { get; } - - /// Initializes a new instance of the class from . - public ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolSystemMessageAppendConfig = value; - } - - /// Converts to . - public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) => new(value); - - /// Initializes a new instance of the class from . - public ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolSystemMessageReplaceConfig = value; - } - - /// Converts to . - public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) => new(value); - - /// Initializes a new instance of the class from . - public ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolSystemMessageCustomizeConfig = value; - } - - /// Converts to . - public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) => new(value); - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ProtocolSystemMessageConfig Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) - { - throw new JsonException("Expected JSON object for ProtocolSystemMessageConfig."); - } - - using var document = JsonDocument.ParseValue(ref reader); - var element = document.RootElement; - if (element.ValueKind == JsonValueKind.Object && (!element.TryGetProperty("mode", out _) || (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "append")))) - { - var protocolSystemMessageAppendConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); - return protocolSystemMessageAppendConfig is null ? throw new JsonException("Expected ProtocolSystemMessageAppendConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageAppendConfig); - } - if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "replace"))) - { - var protocolSystemMessageReplaceConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); - return protocolSystemMessageReplaceConfig is null ? throw new JsonException("Expected ProtocolSystemMessageReplaceConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageReplaceConfig); - } - if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "customize"))) - { - var protocolSystemMessageCustomizeConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); - return protocolSystemMessageCustomizeConfig is null ? throw new JsonException("Expected ProtocolSystemMessageCustomizeConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageCustomizeConfig); - } - - throw new JsonException("JSON value did not match any ProtocolSystemMessageConfig variant."); - } + /// Host the remote points at, for example `github.com` or a GitHub Enterprise hostname. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// - public override void Write(Utf8JsonWriter writer, ProtocolSystemMessageConfig value, JsonSerializerOptions options) - { - if (value.ProtocolSystemMessageAppendConfig is { } protocolSystemMessageAppendConfig) - { - JsonSerializer.Serialize(writer, protocolSystemMessageAppendConfig, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); - return; - } - if (value.ProtocolSystemMessageReplaceConfig is { } protocolSystemMessageReplaceConfig) - { - JsonSerializer.Serialize(writer, protocolSystemMessageReplaceConfig, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); - return; - } - if (value.ProtocolSystemMessageCustomizeConfig is { } protocolSystemMessageCustomizeConfig) - { - JsonSerializer.Serialize(writer, protocolSystemMessageCustomizeConfig, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); - return; - } + /// Repository name, without the owner prefix or the `.git` suffix. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - throw new JsonException("No ProtocolSystemMessageConfig variant value is set."); - } - } + /// Repository owner login (user or organization). + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; } -/// A BYOK model definition referencing a named provider. +/// The GitHub repository that owns the requested path, when the selected remote (`origin`, else the first) is on a GitHub host. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderModelConfig +internal sealed class GitHubRepositoryAtPathResult { - /// Optional capability overrides (vision, tool_calls, reasoning, etc.). - [JsonPropertyName("capabilities")] - public ModelCapabilitiesOverride? Capabilities { get; set; } + /// Resolved repository identity, or null when the selected remote resolves to no GitHub host. + [JsonPropertyName("repository")] + public GitHubRepositoryIdentity? Repository { get; set; } +} - /// Provider-local model id, unique within its provider. The session-wide selection id (shown in the model list and passed to switchTo) is the provider-qualified `provider/id`. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; +/// Working-tree path whose owning GitHub repository should be resolved. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GitHubRepositoryAtPathRequest +{ + /// Absolute path to a directory inside the git working tree to resolve. + [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("path")] + public string Path { get; set; } = string.Empty; +} - /// Maximum context window tokens for the model. - [JsonPropertyName("maxContextWindowTokens")] - public double? MaxContextWindowTokens { get; set; } +/// A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GitHubOwnersRequestIdResult +{ + /// Request id to pass to `gitHubOwners.list` and, to abandon it, `gitHubOwners.cancel`. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } +} - /// Maximum output tokens for the model. - [JsonPropertyName("maxOutputTokens")] - public double? MaxOutputTokens { get; set; } +/// A GitHub login the authenticated user may act as: their own account, or an organization they belong to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GitHubOwnerOption +{ + /// The owner's GitHub login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Maximum prompt/input tokens for the model. - [JsonPropertyName("maxPromptTokens")] - public double? MaxPromptTokens { get; set; } + /// Which kind of owner this is. The authenticated user's own account is always reported as `user`. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; +} - /// Provider-published model metadata, preserved verbatim as the public Model.metadata object. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } +/// Outcome of an owner listing. Exactly one of `owners` and `message` is present, except that `throwError` reports a failure the caller is expected to raise rather than render. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GitHubOwnersListResult +{ + /// Why no owners could be listed, phrased for a user. Present when the listing failed in a way the caller should render rather than raise. + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Well-known base model id used for behavior/capability/config lookup. Defaults to `id`. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// The owners, on success: the authenticated user first, then the organizations they belong to. + [JsonPropertyName("owners")] + public IList? Owners { get; set; } - /// Display name for model pickers. Defaults to the provider-qualified selection id (`provider/id`). - [JsonPropertyName("name")] - public string? Name { get; set; } + /// A malformed request or an unreadable credential, which the caller raises instead of rendering. Kept a field rather than a dispatch error so it stays distinct from `message`, which the caller renders. + [JsonPropertyName("throwError")] + public string? ThrowError { get; set; } - /// Name of the configured provider that serves this model. - [JsonPropertyName("provider")] - public string Provider { get; set; } = string.Empty; + /// A line the caller should log. Present only alongside `message`, and only for failures worth recording. + [JsonPropertyName("warning")] + public string? Warning { get; set; } +} - /// System-message configuration used when the runtime builds the standard prompt for this provider-qualified model, including general-purpose subagents. It uses the same object hierarchy as session-level systemMessage configuration, except transform actions are rejected because the current callback protocol is not model-scoped. When present, it overrides the session-wide configuration on those prompt paths. Selected custom-agent and specialized-subagent prompts remain authoritative. - [JsonPropertyName("systemMessage")] - public ProtocolSystemMessageConfig? SystemMessage { get; set; } +/// Credential to list owners under, and the request id that makes the listing cancellable. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GitHubOwnersListRequest +{ + /// The credential the listing runs under, carried opaquely because its shape is the host's own and the runtime only resolves a token and a GitHub host from it. No credential travels: this selects one the runtime already holds. + [JsonPropertyName("authInfo")] + public JsonElement AuthInfo { get; set; } - /// The model name sent to the provider API for inference. Defaults to `id`. - [JsonPropertyName("wireModel")] - public string? WireModel { get; set; } + /// Request id from `gitHubOwners.nextRequestId`. An id that was never registered, canceled before use, released after being abandoned, or already used is refused rather than silently running uncancellable. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// Azure-specific provider options. +/// Whether the id named a running owner listing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderConfigAzure +internal sealed class GitHubOwnersCancelResult { - /// API version. When set, uses the versioned deployment route. When omitted, uses the GA versionless v1 route. - [JsonPropertyName("apiVersion")] - public string? ApiVersion { get; set; } + /// True when a listing with the id was running and the cancel stopped it. False when the id was never registered, was registered but unused, was released after being abandoned, or its listing had ended. An unused id is released and cannot start a later listing. + [JsonPropertyName("canceled")] + public bool Canceled { get; set; } } -/// External SDK input for a named custom model provider. Ingested by the native protocol boundary before host dispatch. +/// The owner listing to abandon. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class NamedProviderConfig +internal sealed class GitHubOwnersCancelRequest { - /// Static API key used to authenticate provider requests. - [JsonPropertyName("apiKey")] - public string? ApiKey { get; set; } + /// Request id the listing was started with. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } +} - /// Azure authentication configuration for the provider. - [JsonPropertyName("azure")] - public ProviderConfigAzure? Azure { get; set; } +/// The remote the checked-out branch tracks. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GitCurrentBranchRemoteResult +{ + /// Name of the tracked remote. Reports `origin` whenever the working tree has no tracking configuration to read, including on a detached HEAD, so this is never null and never empty. + [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("remote")] + public string Remote { get; set; } = string.Empty; +} - /// Base URL for provider API requests. - [JsonPropertyName("baseUrl")] - public string BaseUrl { get; set; } = string.Empty; +/// Working-tree path a git query applies to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GitCwdRequest +{ + /// Absolute path to a directory inside the git working tree to query. + [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("cwd")] + public string Cwd { get; set; } = string.Empty; +} - /// Static bearer token used to authenticate provider requests. - [JsonPropertyName("bearerToken")] - public string? BearerToken { get; set; } +/// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionWorkingDirectoryContext +{ + /// Merge-base commit SHA (fork point from the remote default branch). + [JsonPropertyName("baseCommit")] + public string? BaseCommit { get; set; } - /// Whether the host supplies bearer tokens dynamically. - [JsonPropertyName("hasBearerTokenProvider")] - public bool? HasBearerTokenProvider { get; set; } + /// Current git branch name. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Additional HTTP headers included with provider requests. - [JsonPropertyName("headers")] - public IDictionary? Headers { get; set; } + /// Current working directory path. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// The product serving the provider's models, reported in telemetry as `model_provider`. Only affects telemetry. - [JsonPropertyName("modelProvider")] - public ProviderConfigModelProvider? ModelProvider { get; set; } + /// Root directory of the git repository, resolved via git rev-parse. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } - /// Unique provider name used to qualify model selection IDs. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Head commit of the current git branch. + [JsonPropertyName("headCommit")] + public string? HeadCommit { get; set; } - /// Transport used to communicate with the provider. - [JsonPropertyName("transport")] - public ProviderConfigTransport? Transport { get; set; } + /// Hosting platform type of the repository. + [JsonPropertyName("hostType")] + public SessionWorkingDirectoryContextHostType? HostType { get; set; } - /// Provider protocol family. - [JsonPropertyName("type")] - public ProviderConfigType? Type { get; set; } + /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). + [JsonPropertyName("repository")] + public string? Repository { get; set; } - /// Wire API used to communicate with the provider. - [JsonPropertyName("wireApi")] - public ProviderConfigWireApi? WireApi { get; set; } + /// Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com"). + [JsonPropertyName("repositoryHost")] + public string? RepositoryHost { get; set; } } -/// Provider configuration prepared from a discovered model. Preparing a plan changes nothing: it neither registers the model with the session nor writes durable configuration. To apply it, pass `provider` and `model` to `session.provider.add`, omitting whichever the dispositions report as already configured. +/// A GitHub repository one of a working tree's remotes points at. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderConfigurationPlan +internal sealed class GitRemoteRepository { - /// Model definition prepared from the discovered model. Capability fields the provider did not report stay omitted rather than being asserted false. - [JsonPropertyName("model")] - public ProviderModelConfig Model { get => field ??= new(); set; } - - /// Whether `model` still needs to be registered. When `alreadyConfigured`, `selectionId` is already registered and the caller can select it without adding anything. - [JsonPropertyName("modelDisposition")] - public ModelProviderConfigurationDisposition ModelDisposition { get; set; } - - /// Provider connection prepared from the instance's inference metadata. Carries no credential; supply one if the endpoint requires it. - [JsonPropertyName("provider")] - public NamedProviderConfig Provider { get => field ??= new(); set; } + /// GitHub host serving the repository, which is not `github.com` for a GitHub Enterprise remote. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Whether `provider` still needs to be registered. When `alreadyConfigured`, a provider with the same endpoint is already registered and `provider` restates it under its existing name; adding it again is rejected as a duplicate. - [JsonPropertyName("providerDisposition")] - public ModelProviderConfigurationDisposition ProviderDisposition { get; set; } + /// Repository name, without the owner. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Provider-qualified selection id (`provider/id`) to pass to `switchTo` once the plan is applied. - [JsonPropertyName("selectionId")] - public string SelectionId { get; set; } = string.Empty; + /// Account or organization owning the repository. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; - /// Non-fatal warnings carried over from the discovered model, such as capabilities the provider did not report. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// Name of the first remote that produced this distinct repository entry, such as `origin` or `upstream`. + [JsonPropertyName("remoteName")] + public string RemoteName { get; set; } = string.Empty; } -/// A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`. +/// The GitHub repositories a working tree's remotes point at. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderPrepareConfigurationRequest +internal sealed class GitReposFromRemotesResult { - /// The discovered instance that serves the model. - [JsonPropertyName("instance")] - public ModelProviderInstance Instance { get => field ??= new(); set; } - - /// The discovered model to configure. - [JsonPropertyName("model")] - public DiscoveredModel Model { get => field ??= new(); set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// One entry per distinct GitHub repository, in the order git reports the first remote for each repository. Empty when no remote points at a GitHub host, which a caller should read as `not connected to GitHub`. Failing to read the remotes is an error, not an empty list. + [JsonPropertyName("repositories")] + public IList Repositories { get => field ??= []; set; } } -/// Managed sandbox enforcement state for a session. +/// Git working tree whose GitHub remotes should be listed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxEnforcementStatus +internal sealed class GitReposFromRemotesRequest { - /// Whether an enforcement failure has permanently blocked the session. - [JsonPropertyName("blocked")] - public bool Blocked { get; set; } - - /// The first sandbox enforcement failure that blocked the session. - [JsonPropertyName("reason")] - public string? Reason { get; set; } - - /// Whether the effective managed policy requires an available sandbox backend. - [JsonPropertyName("required")] - public bool Required { get; set; } + /// Absolute path to the root of the git working tree. + [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("gitRoot")] + public string GitRoot { get; set; } = string.Empty; } -/// Identifies the target session. +/// Indicates whether the calling client was registered as the session filesystem provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSandboxGetEnforcementStatusRequest +public sealed class SessionFsSetProviderResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the provider was set successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Result of attempting to disable sandboxing for the current session. +/// Optional capabilities declared by the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxDisableForSessionResult +public sealed class SessionFsSetProviderCapabilities { - /// The authoritative sandbox enabled state after the operation. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Whether the provider supports binary reads and writes through sessionFs.readFileBytes and sessionFs.writeFileBytes. + [JsonPropertyName("binary")] + public bool? Binary { get; set; } - /// Whether this call resolved the pending request and applied the session opt-out. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the provider supports SQLite query/exists operations. + [JsonPropertyName("sqlite")] + public bool? Sqlite { get; set; } } -/// Optional informational context describing how and where the permission decision was made. This does not affect permission behavior. +/// Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionDecisionContext +internal sealed class SessionFsSetProviderRequest { - /// Disposition of the permission request as observed by the responding client. - [JsonPropertyName("outcome")] - public PermissionDecisionOutcome Outcome { get; set; } + /// Optional capabilities declared by the provider. + [JsonPropertyName("capabilities")] + public SessionFsSetProviderCapabilities? Capabilities { get; set; } - /// Whether the responding client could ask a user interactively, was running headlessly, or had no response path. Omit when the client cannot determine this authoritatively. - [JsonPropertyName("responseCapability")] - public PermissionResponseCapability? ResponseCapability { get; set; } + /// Path conventions used by this filesystem. + [JsonPropertyName("conventions")] + public SessionFsSetProviderConventions Conventions { get; set; } - /// Controlled reason or actor responsible for the response. - [JsonPropertyName("source")] - public PermissionDecisionSource Source { get; set; } + /// Absolute initial working directory for sessions. Registering the provider establishes this path as the root of its virtual namespace; the runtime does not require the provider to materialize or stat it before creating a session. + [JsonPropertyName("initialCwd")] + public string InitialCwd { get; set; } = string.Empty; - /// Client surface that submitted the response. - [JsonPropertyName("surface")] - public PermissionDecisionSurface Surface { get; set; } + /// Path within each session's SessionFs where the runtime stores files for that session. + [JsonPropertyName("sessionStatePath")] + public string SessionStatePath { get; set; } = string.Empty; } -/// Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. +/// Indicates whether the calling client was registered as the LLM inference provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SandboxDisableForSessionRequest +public sealed class LlmInferenceSetProviderResult { - /// Optional attribution for the permission decision. - [JsonPropertyName("decisionContext")] - public PermissionDecisionContext? DecisionContext { get; set; } - - /// Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the provider was set successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Result of accepting a sandbox path grant. +/// Whether the start frame was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxGrantPathForRequestResult +public sealed class LlmInferenceHttpResponseStartResult { - /// Whether this call resolved the pending request and added the path to the session's sandbox policy. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// True when the response start was matched to a pending request; false when unknown. + [JsonPropertyName("accepted")] + public bool Accepted { get; set; } } -/// Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. +/// Response head. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SandboxGrantPathForRequestRequest +internal sealed class LlmInferenceHttpResponseStartRequest { - /// Optional attribution for the permission decision. - [JsonPropertyName("decisionContext")] - public PermissionDecisionContext? DecisionContext { get; set; } + /// HTTP response headers, preserving multiple values per name. + [JsonPropertyName("headers")] + public IDictionary> Headers { get => field ??= new Dictionary>(); set; } - /// Identifier of the exact pending sandbox escalation permission request whose sandboxPathGrant to accept. + /// Matches the requestId from the originating httpRequestStart frame. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// HTTP status code. + [JsonPropertyName("status")] + public long Status { get; set; } + + /// Optional HTTP status reason phrase. + [JsonPropertyName("statusText")] + public string? StatusText { get; set; } } -/// Authentication status and account metadata for the session. +/// Whether the chunk was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionAuthStatus +public sealed class LlmInferenceHttpResponseChunkResult { - /// Authentication type. - [JsonPropertyName("authType")] - public AuthInfoType? AuthType { get; set; } - - /// Copilot plan tier (e.g., individual_pro, business). - [JsonPropertyName("copilotPlan")] - public string? CopilotPlan { get; set; } - - /// Authentication host URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public string? Host { get; set; } - - /// Whether the session has resolved authentication. - [JsonPropertyName("isAuthenticated")] - public bool IsAuthenticated { get; set; } - - /// Authenticated login/username, if available. - [JsonPropertyName("login")] - public string? Login { get; set; } - - /// Human-readable authentication status description. - [JsonPropertyName("statusMessage")] - public string? StatusMessage { get; set; } -} - -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthGetStatusRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// True when the chunk was matched to a pending request; false when unknown. + [JsonPropertyName("accepted")] + public bool Accepted { get; set; } } -/// Indicates whether the credential update succeeded. +/// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSetCredentialsResult +public sealed class LlmInferenceHttpResponseChunkError { - /// Whether the session ended up with a populated `copilotUser` for the installed credentials. `true` when the supplied credential already carried `copilotUser` or it was successfully re-resolved server-side. `false` when the credential is installed without `copilotUser` — either re-resolution failed, or the variant cannot be re-resolved from the credential alone (only the raw-token variants `token`, `env`, and `gh-cli` can). In both `false` cases the token swap still applied, but plan/quota/billing metadata is degraded. Present whenever a credential was supplied; omitted only when no credential was supplied (no-op call). - [JsonPropertyName("copilotUserResolved")] - public bool? CopilotUserResolved { get; set; } + /// Optional machine-readable error code. + [JsonPropertyName("code")] + public string? Code { get; set; } - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Human-readable failure description. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// Authentication credentials accepted by session.gitHubAuth.setCredentials. Session-owned token-provider identities cannot be installed through this method. -/// Polymorphic base type discriminated by type. +/// A response body chunk or terminal error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SettableAuthInfoHmac), "hmac")] -[JsonDerivedType(typeof(SettableAuthInfoEnv), "env")] -[JsonDerivedType(typeof(SettableAuthInfoToken), "token")] -[JsonDerivedType(typeof(SettableAuthInfoCopilotApiToken), "copilot-api-token")] -[JsonDerivedType(typeof(SettableAuthInfoUser), "user")] -[JsonDerivedType(typeof(SettableAuthInfoGhCli), "gh-cli")] -[JsonDerivedType(typeof(SettableAuthInfoApiKey), "api-key")] -public partial class SettableAuthInfo +internal sealed class LlmInferenceHttpResponseChunkRequest { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} - + /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. + [JsonPropertyName("binary")] + public bool? Binary { get; set; } -/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. -/// The hmac variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoHmac : SettableAuthInfo -{ - /// - [JsonIgnore] - public override string Type => "hmac"; + /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty (e.g. when the response body is empty: send a single chunk with empty data and end=true). + [JsonPropertyName("data")] + public string Data { get; set; } = string.Empty; - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// When true, this is the final body chunk for the response. The runtime treats the response body as complete after receiving an end-marked chunk. + [JsonPropertyName("end")] + public bool? End { get; set; } - /// HMAC secret used to sign requests. - [JsonPropertyName("hmac")] - public required string Hmac { get; set; } + /// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. + [JsonPropertyName("error")] + public LlmInferenceHttpResponseChunkError? Error { get; set; } - /// Authentication host. HMAC auth always targets the public GitHub host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Matches the requestId from the originating httpRequestStart frame. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; } -/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. -/// The env variant of . +/// Pre-resolved working-directory context for session startup. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoEnv : SettableAuthInfo +public sealed class SessionContext { - /// - [JsonIgnore] - public override string Type => "env"; - - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Active git branch. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Name of the environment variable the token was sourced from. - [JsonPropertyName("envVar")] - public required string EnvVar { get; set; } + /// Most recent working directory for this session. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// Authentication host (e.g. https://github.com or a GHES host). - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Git repository root, if the cwd was inside a git repo. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } - /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Repository host type. + [JsonPropertyName("hostType")] + public SessionContextHostType? HostType { get; set; } - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// Repository slug in `owner/name` form, when known. + [JsonPropertyName("repository")] + public string? Repository { get; set; } } -/// Token authentication accepted by session.gitHubAuth.setCredentials. -/// The token variant of . +/// GitHub repository the remote session belongs to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoToken : SettableAuthInfo +public sealed class RemoteSessionMetadataRepository { - /// - [JsonIgnore] - public override string Type => "token"; - - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Branch associated with the remote session. + [JsonPropertyName("branch")] + public string Branch { get; set; } = string.Empty; - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Repository name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// Repository owner. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; } -/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. -/// The copilot-api-token variant of . +/// Remote session metadata for the session to hand off (typically obtained from `sessions.list` with `source: "remote"`). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoCopilotApiToken : SettableAuthInfo +public sealed class RemoteSessionMetadataValue { - /// - [JsonIgnore] - public override string Type => "copilot-api-token"; + /// Most recent working directory context. + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. + [JsonPropertyName("hostActivity")] + public string? HostActivity { get; set; } - /// Authentication host (always the public GitHub host). - [JsonPropertyName("host")] - public required string Host { get; set; } -} + /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. + [JsonPropertyName("hostStatus")] + public RemoteSessionHostStatus? HostStatus { get; set; } -/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. -/// The user variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoUser : SettableAuthInfo -{ - /// - [JsonIgnore] - public override string Type => "user"; + /// Always true for remote sessions. + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Last-modified time as an ISO 8601 timestamp. + [JsonPropertyName("modifiedTime")] + public string ModifiedTime { get; set; } = string.Empty; - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Optional human-friendly name set via /rename. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// OAuth user login. - [JsonPropertyName("login")] - public required string Login { get; set; } -} + /// Pull request number associated with the session. + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } -/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. -/// The gh-cli variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoGhCli : SettableAuthInfo -{ - /// - [JsonIgnore] - public override string Type => "gh-cli"; + /// Backing remote session IDs (most recent first). + [JsonPropertyName("remoteSessionIds")] + public IList RemoteSessionIds { get => field ??= []; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// GitHub repository the remote session belongs to. + [JsonPropertyName("repository")] + public RemoteSessionMetadataRepository Repository { get => field ??= new(); set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Original remote resource identifier (task ID or PR node ID). + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } - /// User login as reported by `gh auth status`. - [JsonPropertyName("login")] - public required string Login { get; set; } + /// Stable session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// The token returned by `gh auth token`. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } -} + /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. + [JsonPropertyName("staleAt")] + public string? StaleAt { get; set; } -/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. -/// The api-key variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoApiKey : SettableAuthInfo -{ - /// - [JsonIgnore] - public override string Type => "api-key"; + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("startTime")] + public string StartTime { get; set; } = string.Empty; - /// The API key. Treat as a secret. - [JsonPropertyName("apiKey")] - public required string ApiKey { get; set; } + /// Server-side task state returned by GitHub. + [JsonPropertyName("state")] + public string? State { get; set; } - /// 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. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Short summary of the session, when one has been derived. + [JsonPropertyName("summary")] + public string? Summary { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Whether the remote task originated from CCA or CLI `--remote`. + [JsonPropertyName("taskType")] + public RemoteSessionMetadataTaskType? TaskType { get; set; } } -/// New auth credentials to install on the session. Omit to leave credentials unchanged. +/// `sessions.open` handoff progress update with step, status, and optional message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSetCredentialsParams +public sealed class SessionsOpenProgress { - /// 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 installs the supplied value immediately for outbound model/API requests. When the credential carries a raw token (`token`, `env`, or `gh-cli`) but no `copilotUser`, the runtime additionally re-resolves `copilotUser` server-side (best-effort, asynchronously, after the synchronous install) so plan/quota/billing metadata regains fidelity; on resolution failure the verbatim credential remains installed. It does NOT otherwise validate the credential. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit. - [JsonPropertyName("credentials")] - public SettableAuthInfo? Credentials { get; set; } + /// Optional step message. + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Step status. + [JsonPropertyName("status")] + public SessionsOpenProgressStatus Status { get; set; } + + /// Handoff step. + [JsonPropertyName("step")] + public SessionsOpenProgressStep Step { get; set; } } -/// Credential-free authentication identity safe to expose to hosts and user interfaces. +/// Result of opening a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthIdentity +public sealed class SessionOpenResult { - /// Snapshot of the authenticated user's Copilot subscription info, if known. - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Remote session metadata, present when status is `connected`. + [JsonPropertyName("metadata")] + public RemoteSessionMetadataValue? Metadata { get; set; } - /// Name of the environment variable that supplied the credential, when applicable. - [JsonPropertyName("envVar")] - public string? EnvVar { get; set; } + /// Handoff progress steps, present when status is `handed_off`. + [JsonPropertyName("progress")] + public IList? Progress { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// Remote session ID, present when status is `connected`. + [JsonPropertyName("remoteSessionId")] + public string? RemoteSessionId { get; set; } - /// Authenticated login, when available. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Opened session ID. Omitted when status is `not_found`. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } - /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. - [JsonPropertyName("registrationId")] - public string? RegistrationId { get; set; } + /// Startup prompts queued by user-level hook configs at session creation. Only populated when status is `created`; resumed sessions return an empty array. + [JsonPropertyName("startupPrompts")] + public IList? StartupPrompts { get; set; } - /// Authentication type. - [JsonPropertyName("type")] - public AuthInfoType Type { get; set; } + /// Outcome of the open request. + [JsonPropertyName("status")] + public SessionsOpenStatus Status { get; set; } } -/// Identifies the target session. +/// Identifier and optional friendly name assigned to the newly forked session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthGetCurrentAuthInfoRequest +public sealed class SessionsForkResult { - /// Target session identifier. + /// Friendly name assigned to the forked session, if any. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// The new forked session's ID. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthGetAllAuthAvailableRequest +internal sealed class SessionsForkRequest { - /// Target session identifier. + /// Optional friendly name to assign to the forked session. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Source session ID to fork from. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. + [JsonPropertyName("toEventId")] + public string? ToEventId { get; set; } } -/// Identifies the target session. +/// Repository associated with the connected remote session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthRefreshCopilotUserRequest +public sealed class ConnectedRemoteSessionMetadataRepository { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Branch associated with the remote session. + [JsonPropertyName("branch")] + public string Branch { get; set; } = string.Empty; + + /// Repository name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Repository owner or organization login. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; } -/// Internal GitHub login parameters. +/// Metadata for a connected remote session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAuthLoginRequest +public sealed class ConnectedRemoteSessionMetadata { - /// GitHub host URL. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// Neutral SDK discriminator for the connected remote session kind. + [JsonPropertyName("kind")] + public ConnectedRemoteSessionMetadataKind Kind { get; set; } - /// GitHub login. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; + /// Last session update time as an ISO 8601 string. + [JsonPropertyName("modifiedTime")] + public DateTimeOffset ModifiedTime { get; set; } - /// Whether to persist the token after login. - [JsonPropertyName("persist")] - public bool? Persist { get; set; } + /// Optional friendly session name. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Pull request number associated with the session. + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } - /// GitHub authentication token. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; -} + /// Repository associated with the connected remote session. + [JsonPropertyName("repository")] + public ConnectedRemoteSessionMetadataRepository Repository { get => field ??= new(); set; } -/// Parameters for switching the session's active authentication. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAuthSwitchRequest -{ - /// Authentication information to activate. - [JsonPropertyName("authInfo")] - public AuthInfo AuthInfo { get => field ??= new(); set; } + /// Original remote resource identifier. + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } - /// Target session identifier. + /// SDK session ID for the connected remote session. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Optional token paired with the authentication information. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Remote session staleness deadline as an ISO 8601 string. + [JsonPropertyName("staleAt")] + public DateTimeOffset? StaleAt { get; set; } + + /// Session start time as an ISO 8601 string. + [JsonPropertyName("startTime")] + public DateTimeOffset StartTime { get; set; } + + /// Remote session state returned by the backing service. + [JsonPropertyName("state")] + public string? State { get; set; } + + /// Optional session summary. + [JsonPropertyName("summary")] + public string? Summary { get; set; } } -/// Identifies the target session. +/// Remote session connection result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthLogoutRequest +public sealed class RemoteSessionConnectionResult { - /// Target session identifier. + /// Metadata for a connected remote session. + [JsonPropertyName("metadata")] + public ConnectedRemoteSessionMetadata Metadata { get => field ??= new(); set; } + + /// SDK session ID for the connected remote session. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Parameters identifying a GitHub authentication to log out. +/// Remote session connection parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAuthLogoutUserRequest +internal sealed class ConnectRemoteSessionParams { - /// Authentication information to log out. - [JsonPropertyName("authInfo")] - public AuthInfo AuthInfo { get => field ??= new(); set; } - - /// Target session identifier. + /// Session ID to connect to. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Validation error from an authentication attempt. +/// Local or remote session metadata entry. Narrow on `isRemote` to access source-specific fields. +/// Data type discriminated by isRemote. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthValidationError +public partial class SessionListEntry { - /// Optional message returned by GitHub. - [JsonPropertyName("githubMessage")] - public string? GitHubMessage { get; set; } + /// The boolean discriminator. + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } - /// Authentication validation error message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; -} + /// Runtime client name that created/last resumed this session. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthLastAuthErrorsRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Pre-resolved working-directory context for session startup. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } -/// The enumerated collection, keyed by the same selector as the query. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthEnumerateValueAccounts), "accounts")] -[JsonDerivedType(typeof(AuthEnumerateValueProviders), "providers")] -public partial class AuthEnumerateValue -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("hostActivity")] + public string? HostActivity { get; set; } + /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("hostStatus")] + public RemoteSessionHostStatus? HostStatus { get; set; } -/// One signed-in account in the roster forest. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountStatus -{ - /// Whether this is the active account. - [JsonPropertyName("active")] - public bool Active { get; set; } + /// True for detached maintenance sessions that should be hidden from normal resume lists. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("isDetached")] + public bool? IsDetached { get; set; } - /// Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. - [JsonPropertyName("derivedFrom")] - public string? DerivedFrom { get; set; } + /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mcTaskId")] + public string? McTaskId { get; set; } - /// Authentication host URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// Last-modified time of the session's persisted state, as ISO 8601. + [JsonPropertyName("modifiedTime")] + public required string ModifiedTime { get; set; } - /// The provider kind of this account. - [JsonPropertyName("kind")] - public AccountKind Kind { get; set; } + /// Optional human-friendly name set via /rename. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Authenticated login/username. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; + /// Pull request number associated with the session. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } - /// Opaque selection id used to switch to, or log out, this account. - [JsonPropertyName("selectionId")] - public string SelectionId { get; set; } = string.Empty; + /// Backing remote session IDs (most recent first). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("remoteSessionIds")] + public IList? RemoteSessionIds { get; set; } + + /// GitHub repository the remote session belongs to. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("repository")] + public RemoteSessionMetadataRepository? Repository { get; set; } + + /// Original remote resource identifier (task ID or PR node ID). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } + + /// Stable session identifier. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } + + /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("staleAt")] + public string? StaleAt { get; set; } + + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("startTime")] + public required string StartTime { get; set; } + + /// Server-side task state returned by GitHub. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("state")] + public string? State { get; set; } + + /// Short summary of the session, when one has been derived. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("summary")] + public string? Summary { get; set; } + + /// Whether the remote task originated from CCA or CLI `--remote`. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("taskType")] + public RemoteSessionMetadataTaskType? TaskType { get; set; } } -/// The accounts variant of . +/// Sessions matching the filter, ordered most-recently-modified first. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateValueAccounts : AuthEnumerateValue +public sealed class SessionList { - /// - [JsonIgnore] - public override string Kind => "accounts"; - - /// The signed-in account forest; empty when not logged in. - [JsonPropertyName("items")] - public required IList Items { get; set; } + /// Sessions ordered most-recently-modified first. Discriminated by `isRemote`. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } } -/// A provider offered for interactive login. +/// Optional filter applied to the returned sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderDescriptor +public sealed class SessionListFilter { - /// Whether this provider is currently available to sign in with. - [JsonPropertyName("available")] - public bool Available { get; set; } + /// Match sessions whose context.branch equals this value. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// The neutral provider kind. - [JsonPropertyName("kind")] - public LoginProviderKind Kind { get; set; } + /// Match sessions whose context.cwd equals this value. + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Human-readable menu label, owned by the runtime so every consumer renders identical text. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// Match sessions whose context.gitRoot equals this value. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } + + /// Match sessions whose context.repository equals this value. + [JsonPropertyName("repository")] + public string? Repository { get; set; } } -/// The providers variant of . +/// Optional source filter, metadata-load limit, and context filter applied to the returned sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateValueProviders : AuthEnumerateValue +internal sealed class SessionsListRequest { - /// - [JsonIgnore] - public override string Kind => "providers"; + /// Optional filter applied to the returned sessions. + [JsonPropertyName("filter")] + public SessionListFilter? Filter { get; set; } - /// The providers offered for interactive login. - [JsonPropertyName("items")] - public required IList Items { get; set; } + /// When true, include detached maintenance sessions. Defaults to false for user-facing session lists. + [JsonPropertyName("includeDetached")] + public bool? IncludeDetached { get; set; } + + /// When provided, only the first N local sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every local session. Has no effect on remote entries (which always carry their full shape). + [JsonPropertyName("metadataLimit")] + public long? MetadataLimit { get; set; } + + /// Which session sources to include. Defaults to `local` for backward compatibility. + [JsonPropertyName("source")] + public SessionSource? Source { get; set; } + + /// Only meaningful when `source` includes remote. When true, propagates errors from the remote service instead of silently returning an empty remote list. Defaults to false. + [JsonPropertyName("throwOnError")] + public bool? ThrowOnError { get; set; } } -/// Selects which accounts collection to enumerate. A no-arg selector is the empty-payload variant. -/// Polymorphic base type discriminated by kind. +/// Persisted local session metadata, including identifiers, timestamps, summary/name, client, context, detached state, and task ID. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthEnumerateQueryAccounts), "accounts")] -[JsonDerivedType(typeof(AuthEnumerateQueryProviders), "providers")] -public partial class AuthEnumerateQuery +public sealed class LocalSessionMetadataValue { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Runtime client name that created/last resumed this session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Pre-resolved working-directory context for session startup. + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } + /// True for detached maintenance sessions that should be hidden from normal resume lists. + [JsonPropertyName("isDetached")] + public bool? IsDetached { get; set; } -/// The accounts variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateQueryAccounts : AuthEnumerateQuery -{ - /// - [JsonIgnore] - public override string Kind => "accounts"; + /// Always false for local sessions. + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } + + /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. + [JsonPropertyName("mcTaskId")] + public string? McTaskId { get; set; } + + /// Last-modified time of the session's persisted state, as ISO 8601. + [JsonPropertyName("modifiedTime")] + public string ModifiedTime { get; set; } = string.Empty; + + /// Optional human-friendly name set via /rename. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Stable session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("startTime")] + public string StartTime { get; set; } = string.Empty; + + /// Short summary of the session, when one has been derived. + [JsonPropertyName("summary")] + public string? Summary { get; set; } } -/// The providers variant of . +/// Persisted local session metadata when the session exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateQueryProviders : AuthEnumerateQuery +internal sealed class SessionsGetMetadataResult { - /// - [JsonIgnore] - public override string Kind => "providers"; - - /// Whether an interactive Entra broker is available on the host; gates Entra availability in the returned list. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("brokerAvailable")] - public bool? BrokerAvailable { get; set; } + /// Local session metadata, omitted when the session does not exist. + [JsonPropertyName("session")] + public LocalSessionMetadataValue? Session { get; set; } } -/// Enumerate request carrying the typed collection query. +/// Session ID whose persisted metadata should be read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountsEnumerateRequest +internal sealed class SessionsGetMetadataRequest { - /// Which typed accounts collection to enumerate. - [JsonPropertyName("query")] - public AuthEnumerateQuery Query { get => field ??= new(); set; } - - /// Target session identifier. + /// Session ID to inspect. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The read result, keyed by the same selector as the query. -/// Polymorphic base type discriminated by kind. +/// Client metadata outcome for one requested local session. +/// Polymorphic base type discriminated by status. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", + TypeDiscriminatorPropertyName = "status", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthReadValueActiveAccount), "activeAccount")] -[JsonDerivedType(typeof(AuthReadValueStatus), "status")] -[JsonDerivedType(typeof(AuthReadValueLastErrors), "lastErrors")] -public partial class AuthReadValue +[JsonDerivedType(typeof(SessionsClientMetadataEntryOk), "ok")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryNotFound), "notFound")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryCorrupt), "corrupt")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryUnsupportedVersion), "unsupportedVersion")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryUnavailable), "unavailable")] +public partial class SessionsClientMetadataEntry { /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + [JsonPropertyName("status")] + public virtual string Status { get; set; } = string.Empty; } -/// The activeAccount variant of . +/// The ok variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadValueActiveAccount : AuthReadValue +public partial class SessionsClientMetadataEntryOk : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "activeAccount"; - - /// The active account, or absent when not logged in. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("account")] - public AccountStatus? Account { get; set; } -} - -/// Neutral authentication status summary. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthStatusDto -{ - /// Number of signed-in accounts in the roster. - [JsonPropertyName("accountCount")] - public long AccountCount { get; set; } - - /// Active account host, if authenticated. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("activeHost")] - public string? ActiveHost { get; set; } - - /// Active account login, if authenticated. - [JsonPropertyName("activeLogin")] - public string? ActiveLogin { get; set; } + public override string Status => "ok"; - /// Copilot plan tier of the active account, if known. - [JsonPropertyName("copilotPlan")] - public string? CopilotPlan { get; set; } + /// Validated client metadata, possibly empty or projected to requested keys. + [JsonPropertyName("metadata")] + public required IDictionary Metadata { get; set; } - /// Whether the session has resolved authentication. - [JsonPropertyName("isAuthenticated")] - public bool IsAuthenticated { get; set; } + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// The status variant of . +/// The notFound variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadValueStatus : AuthReadValue +public partial class SessionsClientMetadataEntryNotFound : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "status"; + public override string Status => "notFound"; - /// The neutral authentication status summary. - [JsonPropertyName("status")] - public required AuthStatusDto Status { get; set; } + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// The lastErrors variant of . +/// The corrupt variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadValueLastErrors : AuthReadValue +public partial class SessionsClientMetadataEntryCorrupt : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "lastErrors"; + public override string Status => "corrupt"; - /// Validation errors from the most recent authentication attempt. - [JsonPropertyName("errors")] - public required IList Errors { get; set; } + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// Selects which typed accounts datum to read. -/// Polymorphic base type discriminated by kind. +/// The unsupportedVersion variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthReadQueryActiveAccount), "activeAccount")] -[JsonDerivedType(typeof(AuthReadQueryStatus), "status")] -[JsonDerivedType(typeof(AuthReadQueryLastErrors), "lastErrors")] -public partial class AuthReadQuery +public partial class SessionsClientMetadataEntryUnsupportedVersion : SessionsClientMetadataEntry { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Status => "unsupportedVersion"; + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } +} -/// The activeAccount variant of . +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadQueryActiveAccount : AuthReadQuery +public partial class SessionsClientMetadataEntryUnavailable : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "activeAccount"; + public override string Status => "unavailable"; + + /// Filesystem or provider error code. Clients should not assume every provider uses operating-system error codes. + [JsonPropertyName("code")] + public required string Code { get; set; } + + /// Human-readable diagnostic message. Not stable for programmatic matching. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// The status variant of . +/// Bounded batch request for client-owned metadata from persisted local sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadQueryStatus : AuthReadQuery +internal sealed class SessionsGetClientMetadataRequest { - /// - [JsonIgnore] - public override string Kind => "status"; + /// Case-sensitive keys to project from each valid bag. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Omit to return every entry. + [JsonPropertyName("keys")] + public IList? Keys { get; set; } + + /// Session IDs to inspect. Results preserve this order. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } } -/// The lastErrors variant of . +/// Batch of session events returned by a read, with cursor and continuation metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadQueryLastErrors : AuthReadQuery +public sealed class EventsReadResult { - /// - [JsonIgnore] - public override string Kind => "lastErrors"; + /// Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue from where this read left off. Always present, even when no events were returned. For a backward read this cursor pages toward OLDER events; keep passing `direction: backward` with it (the cursor is also self-describing, so backward paging continues correctly). + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; + + /// Cursor status: 'ok' means the cursor was applied successfully. For session.eventLog.read, 'expired' means the cursor referred to an event that no longer exists in active history and the read fell back to a boundary of the remaining history: the beginning for a forward read or the newest window for a backward read. That fallback may overlap already rendered events, so active-session consumers should reset, rebase, or deduplicate before continuing. sessions.readPersistedEvents has stricter snapshot semantics: 'expired' returns an empty terminal page and never switches to a replacement journal generation. Other persisted-read I/O failures are RPC errors with diagnostics, not cursor expiry. + [JsonPropertyName("cursorStatus")] + public EventsCursorStatus CursorStatus { get; set; } + + /// Session events for this batch, merged into a single stream in creation order: durable (persisted) events and ephemeral events interleave exactly as they were emitted. Set `includeEphemeral: false` to receive only durable events. Ephemeral events are never replayable once pruned from the in-memory ring, so a consumer that needs them should keep reading with a non-zero `waitMs`. For a backward (tail-first) read, the returned window contains persisted events only, still in chronological (oldest-to-newest) append order. + [JsonPropertyName("events")] + public IList Events { get => field ??= []; set; } + + /// True when more events are available in the read's direction. For a backward read, true means older persisted events remain before the returned window. A persisted-event page may contain fewer than `max` events because of its byte budget while still reporting hasMore true; continue according to this flag rather than the event count. + [JsonPropertyName("hasMore")] + public bool HasMore { get; set; } } -/// Read request carrying the typed datum query. +/// Pagination options for reading an inactive or active local session's persisted event journal. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountsGetRequest +internal sealed class SessionsReadPersistedEventsRequest { - /// Which typed accounts datum to read. - [JsonPropertyName("query")] - public AuthReadQuery Query { get => field ??= new(); set; } + /// Opaque, process-local, single-use cursor returned by the previous persisted-event read. Omit on the first call and issue continuations sequentially; reusing the same cursor returns an expired terminal page. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } - /// Target session identifier. + /// Direction to page through persisted history. Forward starts at the beginning; backward starts with the newest events. Events in each page remain chronological. This selects the initial read only; a continuation always uses the direction bound into its cursor. + [JsonPropertyName("direction")] + public EventsReadDirection? Direction { get; set; } + + /// Maximum number of events to return in this batch (1–1000, default 200). Pages may contain fewer events to keep the serialized event array within a soft 1 MiB budget including resolved binary assets; one oversized event is returned alone to guarantee progress. + [JsonPropertyName("max")] + public long? Max { get; set; } + + /// Session ID whose persisted event journal should be read. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of a non-interactive accounts mutation. +/// Recent local session IDs that contain user-visible history. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthWriteResult +internal sealed class SessionsListNonEmptySessionIdsResult { - /// For a logout, whether other signed-in accounts remain. - [JsonPropertyName("moreUsers")] - public bool? MoreUsers { get; set; } - - /// Whether the mutation was applied. - [JsonPropertyName("ok")] - public bool Ok { get; set; } + /// Session IDs ordered newest-first. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } } -/// One non-interactive accounts mutation command (the selector is fused with its typed args). -/// Polymorphic base type discriminated by kind. +/// Limit for non-empty local session IDs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthWriteSwitchActive), "switchActive")] -[JsonDerivedType(typeof(AuthWriteLogout), "logout")] -[JsonDerivedType(typeof(AuthWriteSetCredentials), "setCredentials")] -public partial class AuthWrite +internal sealed class SessionsListNonEmptySessionIdsRequest { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Maximum number of session IDs to return. + [JsonPropertyName("limit")] + public long? Limit { get; set; } } - -/// The switchActive variant of . +/// ID of the local session bound to the given GitHub task, or omitted when none. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthWriteSwitchActive : AuthWrite +public sealed class SessionsFindByTaskIDResult { - /// - [JsonIgnore] - public override string Kind => "switchActive"; - - /// Opaque selection id of the account to make active. - [JsonPropertyName("selectionId")] - public required string SelectionId { get; set; } + /// Omitted when no local session is bound to that GitHub task. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } } -/// The logout variant of . +/// GitHub task ID to look up. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthWriteLogout : AuthWrite +internal sealed class SessionsFindByTaskIDRequest { - /// - [JsonIgnore] - public override string Kind => "logout"; - - /// Opaque selection id of the account to log out; absent logs out the active account. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// GitHub task ID to look up. + [JsonPropertyName("taskId")] + public string TaskId { get; set; } = string.Empty; } -/// The setCredentials variant of . +/// Session ID matching the prefix, omitted when no unique match exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthWriteSetCredentials : AuthWrite +public sealed class SessionsFindByPrefixResult { - /// - [JsonIgnore] - public override string Kind => "setCredentials"; + /// Omitted when no unique session matches the prefix (no match or ambiguous). + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } +} - /// Authentication host URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public required string Host { get; set; } - - /// Login/username for the credential. - [JsonPropertyName("login")] - public required string Login { get; set; } - - /// GitHub authentication token to install. - [JsonPropertyName("token")] - public required string Token { get; set; } +/// UUID prefix to resolve to a unique session ID. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsFindByPrefixRequest +{ + /// UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. + [JsonPropertyName("prefix")] + public string Prefix { get; set; } = string.Empty; } -/// Mutation request carrying the typed write command. +/// Most-relevant session ID for the supplied context, or omitted when no sessions exist. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountsSetRequest +public sealed class SessionsGetLastForContextResult { - /// The non-interactive mutation command to apply. - [JsonPropertyName("command")] - public AuthWrite Command { get => field ??= new(); set; } - - /// Target session identifier. + /// Most-relevant session ID for the supplied context, or omitted when no sessions exist. [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public string? SessionId { get; set; } } -/// One step in an interactive login flow. The consumer acts on the step and calls advance to proceed. Browser-open is encoded as two distinct steps by design: `open-url` is CONSUMER-driven (the provider surfaces the authorize URL and the consumer opens it — github.com/GHEC web), while `needs-interaction` is PROVIDER-driven (the provider opens the browser or broker UI itself and does not surface a URL — Entra). -/// Polymorphic base type discriminated by kind. +/// Optional working-directory context used to score session relevance. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthLoginStepOpenUrl), "open-url")] -[JsonDerivedType(typeof(AuthLoginStepInputRequired), "input-required")] -[JsonDerivedType(typeof(AuthLoginStepAwaiting), "awaiting")] -[JsonDerivedType(typeof(AuthLoginStepNeedsInteraction), "needs-interaction")] -[JsonDerivedType(typeof(AuthLoginStepCompleted), "completed")] -[JsonDerivedType(typeof(AuthLoginStepError), "error")] -public partial class AuthLoginStep +internal sealed class SessionsGetLastForContextRequest { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Optional working-directory context used to score session relevance. When omitted the most-recently-modified session wins. + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } } - -/// The open-url variant of . +/// Absolute path to the session's events.jsonl file on disk. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepOpenUrl : AuthLoginStep +internal sealed class SessionsGetEventFilePathResult { - /// - [JsonIgnore] - public override string Kind => "open-url"; - - /// Authorize URL the consumer should open in a browser (consumer-driven browser-open). - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Absolute path to the session's events.jsonl file. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; } -/// The input-required variant of . +/// Session ID whose event-log file path to compute. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepInputRequired : AuthLoginStep +internal sealed class SessionsGetEventFilePathRequest { - /// - [JsonIgnore] - public override string Kind => "input-required"; - - /// Prompt for the value the provider needs; the consumer supplies it as advance input (e.g. a GitHub Enterprise Cloud host, *.ghe.com). - [JsonPropertyName("prompt")] - public required string Prompt { get; set; } + /// Session ID whose event-log file path to compute. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The awaiting variant of . +/// Map of sessionId -> on-disk size in bytes for each session's workspace directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepAwaiting : AuthLoginStep +public sealed class SessionSizes { - /// - [JsonIgnore] - public override string Kind => "awaiting"; + /// Map of sessionId -> on-disk size in bytes for the session's workspace directory. + [JsonPropertyName("sizes")] + public IDictionary Sizes { get => field ??= new Dictionary(); set; } } -/// The needs-interaction variant of . +/// Session IDs from the input set that are currently in use by another process. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepNeedsInteraction : AuthLoginStep +public sealed class SessionsCheckInUseResult { - /// - [JsonIgnore] - public override string Kind => "needs-interaction"; + /// Session IDs from the input set that are currently held by another running process via an alive lock file. + [JsonPropertyName("inUse")] + public IList InUse { get => field ??= []; set; } } -/// Terminal result of an interactive login flow. +/// Session IDs to test for live in-use locks. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthLoginResultDto +internal sealed class SessionsCheckInUseRequest { - /// Host that was signed in, when completed. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public string? Host { get; set; } - - /// Login that was signed in, when completed. - [JsonPropertyName("login")] - public string? Login { get; set; } - - /// Terminal disposition of the login. - [JsonPropertyName("status")] - public AuthLoginResultStatus Status { get; set; } + /// Session IDs to test for live in-use locks. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } } -/// The completed variant of . +/// The session's persisted remote-steerable flag, or omitted when no value has been persisted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepCompleted : AuthLoginStep +internal sealed class SessionsGetPersistedRemoteSteerableResult { - /// - [JsonIgnore] - public override string Kind => "completed"; - - /// The terminal login result. - [JsonPropertyName("result")] - public required AuthLoginResultDto Result { get; set; } + /// The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted. + [JsonPropertyName("remoteSteerable")] + public bool? RemoteSteerable { get; set; } } -/// The error variant of . +/// Session ID to look up the persisted remote-steerable flag for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepError : AuthLoginStep +internal sealed class SessionsGetPersistedRemoteSteerableRequest { - /// - [JsonIgnore] - public override string Kind => "error"; - - /// Human-readable failure message. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Session ID to look up the persisted remote-steerable flag for. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A started login flow: its opaque id and first step. +/// 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthLoginBegun +public sealed class SessionsCloseResult { - /// Opaque flow id used to advance or cancel this login. - [JsonPropertyName("flowId")] - public string FlowId { get; set; } = string.Empty; - - /// The first step of the flow. - [JsonPropertyName("step")] - public AuthLoginStep Step { get => field ??= new(); set; } } -/// Begin an interactive login flow for a provider kind. Dispatch is kind-only. +/// Session ID to close. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AuthLoginBeginRequest +internal sealed class SessionsCloseRequest { - /// The provider kind to sign in with. - [JsonPropertyName("kind")] - public LoginProviderKind Kind { get; set; } - - /// Target session identifier. + /// Session ID to close. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Advance an in-flight login flow, optionally fulfilling an input-required step. +/// Map of sessionId -> bytes freed by removing the session's workspace directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AuthLoginAdvanceRequest +public sealed class SessionBulkDeleteResult { - /// Opaque flow id from begin. - [JsonPropertyName("flowId")] - public string FlowId { get; set; } = string.Empty; - - /// Neutral input fulfilling a preceding input-required step (e.g. a GHEC host); ignored otherwise. - [JsonPropertyName("input")] - public string? Input { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). + [JsonPropertyName("freedBytes")] + public IDictionary FreedBytes { get => field ??= new Dictionary(); set; } } -/// Cancel an in-flight login flow. +/// Session IDs to close, deactivate, and delete from disk. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AuthLoginCancelRequest +internal sealed class SessionsBulkDeleteRequest { - /// Opaque flow id from begin. - [JsonPropertyName("flowId")] - public string FlowId { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Session IDs to close, deactivate, and delete from disk. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } } -/// A file included in the session debug bundle. +/// Session ID to delete from disk. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsCollectedEntry +internal sealed class SessionsDeleteRequest { - /// Relative path of the file in the staged bundle/archive. - [JsonPropertyName("bundlePath")] - public string BundlePath { get; set; } = string.Empty; - - /// Redacted output size in bytes. - [JsonPropertyName("sizeBytes")] - public long SizeBytes { get; set; } + /// Session ID to delete. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Source category for this entry. - [JsonPropertyName("source")] - public DebugCollectLogsSource Source { get; set; } + /// Internal resolved session directory path to delete. + [JsonPropertyName("sessionPath")] + public string? SessionPath { get; set; } } -/// An optional debug bundle entry that could not be included. +/// Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsSkippedEntry +public sealed class SessionPruneResult { - /// Relative path requested for this bundle entry. - [JsonPropertyName("bundlePath")] - public string BundlePath { get; set; } = string.Empty; + /// Session IDs that would be deleted in dry-run mode (always empty otherwise). + [JsonPropertyName("candidates")] + public IList Candidates { get => field ??= []; set; } - /// Server-local source path that could not be read. - [JsonPropertyName("path")] - public string? Path { get; set; } + /// Session IDs that were deleted (always empty in dry-run mode). + [JsonPropertyName("deleted")] + public IList Deleted { get => field ??= []; set; } - /// Reason the entry was skipped. - [JsonPropertyName("reason")] - public string Reason { get; set; } = string.Empty; + /// True when no deletions were actually performed. + [JsonPropertyName("dryRun")] + public bool DryRun { get; set; } + + /// Total bytes freed (actual when not dry-run, projected when dry-run). + [JsonPropertyName("freedBytes")] + public long FreedBytes { get; set; } + + /// Session IDs that were skipped (e.g., named sessions). + [JsonPropertyName("skipped")] + public IList Skipped { get => field ??= []; set; } } -/// Result of collecting a session debug bundle. +/// Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsResult +internal sealed class SessionsPruneOldRequest { - /// Files included in the bundle. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + /// When true, only report what would be deleted without performing any deletion. + [JsonPropertyName("dryRun")] + public bool? DryRun { get; set; } - /// Destination kind that was written. - [JsonPropertyName("kind")] - public DebugCollectLogsResultKind Kind { get; set; } + /// Session IDs that should never be considered for pruning. + [JsonPropertyName("excludeSessionIds")] + public IList? ExcludeSessionIds { get; set; } - /// Actual archive path or staging directory path written. This may differ from the requested path when no-overwrite suffixing or fallback-to-temp-directory was needed. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// When true, named sessions (set via /rename) are also eligible for pruning. + [JsonPropertyName("includeNamed")] + public bool? IncludeNamed { get; set; } - /// Optional files or directories that could not be included. - [JsonPropertyName("skippedEntries")] - public IList? SkippedEntries { get; set; } + /// Delete sessions whose modifiedTime is at least this many days old. + [JsonPropertyName("olderThanDays")] + public long OlderThanDays { get; set; } } -/// A caller-provided server-local file or directory to include in the debug bundle. +/// Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsEntry +public sealed class SessionsSaveResult { - /// Relative path to use inside the staged bundle/archive. - [JsonPropertyName("bundlePath")] - public string BundlePath { get; set; } = string.Empty; - - /// Kind of source path to include. - [JsonPropertyName("kind")] - public DebugCollectLogsEntryKind Kind { get; set; } - - /// Server-local source path to read. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// How text content from this entry should be redacted. Defaults to plain-text. With none, no redaction is applied; the caller must ensure any necessary redaction is performed before this call. - [JsonPropertyName("redaction")] - public DebugCollectLogsRedaction? Redaction { get; set; } - - /// When true, collection fails if this entry cannot be read. Defaults to false, which records the entry in `skippedEntries`. - [JsonPropertyName("required")] - public bool? Required { get; set; } } -/// Destination for the session debug bundle. -/// Polymorphic base type discriminated by kind. +/// Session ID whose pending events should be flushed to disk. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(DebugCollectLogsDestinationArchive), "archive")] -[JsonDerivedType(typeof(DebugCollectLogsDestinationDirectory), "directory")] -public partial class DebugCollectLogsDestination +internal sealed class SessionsSaveRequest { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Session ID whose pending events should be flushed to disk. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } - -/// The archive variant of . +/// 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class DebugCollectLogsDestinationArchive : DebugCollectLogsDestination +public sealed class SessionsReleaseLockResult { - /// - [JsonIgnore] - public override string Kind => "archive"; +} - /// When true, create the archive atomically without overwriting an existing file by appending ` (N)` before the extension as needed. Defaults to false. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("noOverwrite")] - public bool? NoOverwrite { get; set; } +/// Session ID whose in-use lock should be released. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsReleaseLockRequest +{ + /// Session ID whose in-use lock should be released. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Absolute or server-relative path for the .tgz archive to create. - [JsonPropertyName("outputPath")] - public required string OutputPath { get; set; } +/// The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionEnrichMetadataResult +{ + /// Enriched records, with summary and context backfilled. Sessions confirmed empty and unnamed may be omitted. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } } -/// The directory variant of . +/// Session metadata records to enrich with summary and context information. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class DebugCollectLogsDestinationDirectory : DebugCollectLogsDestination +internal sealed class SessionsEnrichMetadataRequest { - /// - [JsonIgnore] - public override string Kind => "directory"; + /// Session metadata records to enrich. Records that already have summary and context are returned unchanged. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } +} - /// Directory where files should be staged. The directory is created if needed. - [JsonPropertyName("outputDirectory")] - public required string OutputDirectory { get; set; } +/// The workspace record that was written. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsCreateWorkspaceResult +{ + /// The created workspace record, as JSON. + [JsonPropertyName("workspaceJson")] + public string WorkspaceJson { get; set; } = string.Empty; } -/// Built-in session diagnostics to include in the bundle. Omitted fields default to true. +/// A working-directory context together with the client that produced it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsInclude +public sealed class SessionWorkingDirectoryContextWithClient { - /// Server-local path to the current process log. When set, it is included as `process.log` and its directory is searched for prior logs from the same session. - [JsonPropertyName("currentProcessLogPath")] - public string? CurrentProcessLogPath { get; set; } + /// Merge-base commit SHA. + [JsonPropertyName("baseCommit")] + public string? BaseCommit { get; set; } - /// Include the session event log (`events.jsonl`). Defaults to true. - [JsonPropertyName("events")] - public bool? Events { get; set; } + /// Current git branch name. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Server-local path to the session's events.jsonl file. Internal callers normally omit this and let the runtime derive it from the session. - [JsonPropertyName("eventsPath")] - public string? EventsPath { get; set; } + /// Name of the client that created the session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// Maximum number of previous process logs to include. Defaults to 5. - [JsonPropertyName("previousProcessLogLimit")] - public long? PreviousProcessLogLimit { get; set; } + /// Current working directory path. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// Server-local process log directory to search when `currentProcessLogPath` is unavailable, useful for collecting logs for inactive sessions. - [JsonPropertyName("processLogDirectory")] - public string? ProcessLogDirectory { get; set; } + /// Root directory of the git repository. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } - /// Include process logs for the session. Defaults to true. - [JsonPropertyName("processLogs")] - public bool? ProcessLogs { get; set; } + /// Head commit of the current git branch. + [JsonPropertyName("headCommit")] + public string? HeadCommit { get; set; } - /// Include interactive shell logs written under the session's `shell-logs` directory. Defaults to true. - [JsonPropertyName("shellLogs")] - public bool? ShellLogs { get; set; } + /// Hosting platform type of the repository. + [JsonPropertyName("hostType")] + public string? HostType { get; set; } + + /// Repository identifier derived from the git remote URL. + [JsonPropertyName("repository")] + public string? Repository { get; set; } + + /// Raw host string from the git remote URL. + [JsonPropertyName("repositoryHost")] + public string? RepositoryHost { get; set; } } -/// Options for collecting a session debug bundle with configurable redaction. +/// Identity, state location and starting context for a workspace record. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DebugCollectLogsRequest +internal sealed class SessionsCreateWorkspaceRequest { - /// Caller-provided server-local files or directories to include in addition to the runtime's built-in session diagnostics. This lets host applications add their own diagnostics without changing the API shape. - [JsonPropertyName("additionalEntries")] - public IList? AdditionalEntries { get; set; } + /// Starting working-directory context. The record keeps `cwd`, `gitRoot`, `repository`, `hostType`, `branch`, and `clientName`. Other fields, including `repositoryHost`, `headCommit`, and `baseCommit`, are ignored. `hostType` must be `github` or `ado`. + [JsonPropertyName("context")] + public SessionWorkingDirectoryContextWithClient? Context { get; set; } - /// Where the bundle should be written. Use `archive` to produce a .tgz, or `directory` to stage files for caller-managed upload/post-processing. - [JsonPropertyName("destination")] - public DebugCollectLogsDestination Destination { get => field ??= new(); set; } + /// `windows` (any letter case) selects Windows path rules. Any other value selects POSIX path rules. + [JsonPropertyName("convention")] + public string Convention { get; set; } = string.Empty; - /// Which built-in session diagnostics to include. Omitted fields default to true. - [JsonPropertyName("include")] - public DebugCollectLogsInclude? Include { get; set; } + /// User-supplied display name for the workspace. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Target session identifier. + /// Session ID the workspace record belongs to. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Directory the session's state is written under when no session filesystem provider is configured. Ignored when a provider is configured; the provider's session state path is used instead. + [JsonPropertyName("sessionStatePath")] + public string SessionStatePath { get; set; } = string.Empty; } -/// Canvas action that the agent or host can invoke. To discover the input schema for a particular action, call the list_canvas_capabilities tool. +/// The workspace record on disk, omitted when the session has none. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasAction +internal sealed class SessionsLoadWorkspaceResult { - /// Description of the action. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// JSON Schema for the action input. - [JsonPropertyName("inputSchema")] - public JsonElement? InputSchema { get; set; } - - /// Action name exposed by the canvas provider. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The workspace record, as JSON. Omitted when the record does not exist. + [JsonPropertyName("workspaceJson")] + public string? WorkspaceJson { get; set; } } -/// Canvas available in the current session. +/// Where the session's state lives, as a root directory and the session ID under it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredCanvas +internal sealed class SessionsLoadWorkspaceRequest { - /// Actions the agent or host may invoke on an open instance. - [JsonPropertyName("actions")] - public IList? Actions { get; set; } - - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; - - /// Short, single-sentence description shown to the agent in canvas catalogs. - [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("description")] - public string Description { get; set; } = string.Empty; + /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Human-readable canvas name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// Root directory every session's state directory sits under. + [JsonPropertyName("sessionsHome")] + public string SessionsHome { get; set; } = string.Empty; +} - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; +/// The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsUpdateWorkspaceFieldsResult +{ +} - /// Owning extension display name, when available. - [JsonPropertyName("extensionName")] - public string? ExtensionName { get; set; } +/// Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsUpdateWorkspaceFieldsRequest +{ + /// Workspace-schema fields to merge into the record, as a JSON object. Fields the object omits keep their stored values, except stored keys outside the schema are not preserved and a stored `fork_count` is never replaced. + [JsonPropertyName("fieldsJson")] + public string FieldsJson { get; set; } = string.Empty; - /// Host-local PNG path for the canvas icon, when supplied. - [JsonPropertyName("icon")] - public string? Icon { get; set; } + /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// JSON Schema for canvas open input. - [JsonPropertyName("inputSchema")] - public JsonElement? InputSchema { get; set; } + /// Root directory every session's state directory sits under. + [JsonPropertyName("sessionsHome")] + public string SessionsHome { get; set; } = string.Empty; } -/// Declared canvases available in this session. +/// 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasList +public sealed class SessionsReloadPluginHooksResult { - /// Declared canvases available in this session. - [JsonPropertyName("canvases")] - public IList Canvases { get => field ??= []; set; } } -/// Identifies the target session. +/// Active session ID and an optional flag for deferring repo-level hooks until folder trust. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCanvasListRequest +internal sealed class SessionsReloadPluginHooksRequest { - /// Target session identifier. + /// When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. + [JsonPropertyName("deferRepoHooks")] + public bool? DeferRepoHooks { get; set; } + + /// Active session ID to reload hooks for. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Open canvas instance snapshot. +/// Queued repo-level startup prompts and the total hook command count after loading. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OpenCanvasInstance +public sealed class SessionLoadDeferredRepoHooksResult { - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; - - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. + [JsonPropertyName("hookCount")] + public long HookCount { get; set; } - /// Owning extension display name, when available. - [JsonPropertyName("extensionName")] - public string? ExtensionName { get; set; } - - /// Host-local PNG path for the canvas icon, when supplied. - [JsonPropertyName("icon")] - public string? Icon { get; set; } - - /// Input supplied when the instance was opened. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } - - /// Stable caller-supplied canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; - - /// Provider-supplied status text. - [JsonPropertyName("status")] - public string? Status { get; set; } - - /// Rendered title. - [JsonPropertyName("title")] - public string? Title { get; set; } - - /// URL for web-rendered canvases. - [JsonPropertyName("url")] - public string? Url { get; set; } -} - -/// Live open-canvas snapshot. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasListOpenResult -{ - /// Currently open canvas instances. - [JsonPropertyName("openCanvases")] - public IList OpenCanvases { get => field ??= []; set; } -} - -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCanvasListOpenRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} - -/// Canvas open parameters. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasOpenRequest -{ - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; - - /// Owning provider identifier. Optional when the canvasId is unique across providers; required to disambiguate when multiple providers register the same canvasId. - [JsonPropertyName("extensionId")] - public string? ExtensionId { get; set; } - - /// Canvas open input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } - - /// Caller-supplied stable instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. + [JsonPropertyName("startupPrompts")] + public IList StartupPrompts { get => field ??= []; set; } } -/// Canvas close parameters. +/// Active session ID whose deferred repo-level hooks should be loaded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasCloseRequest +internal sealed class SessionsLoadDeferredRepoHooksRequest { - /// Open canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; - - /// Target session identifier. + /// Active session ID whose deferred repo-level hooks should be loaded. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Canvas action invocation result. +/// 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasActionInvokeResult +public sealed class SessionsSetAdditionalPluginsResult { - /// Provider-supplied action result. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } } -/// Canvas action invocation parameters. +/// Manager-wide additional plugins to register; replaces any previously-configured set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasActionInvokeRequest +internal sealed class SessionsSetAdditionalPluginsRequest { - /// Action name to invoke. - [JsonPropertyName("actionName")] - public string ActionName { get; set; } = string.Empty; - - /// Action input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } - - /// Open canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } } -/// Internal canvas provider registration parameters. +/// Dynamic-context board entry count, when available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasProviderRegisterRequest +internal sealed class SessionsGetBoardEntryCountResult { - /// Canvas contributions supplied by the provider. - [JsonPropertyName("canvases")] - public IList Canvases { get => field ??= []; set; } - - /// Connection identifier for callback routing. - [JsonPropertyName("connectionId")] - public string ConnectionId { get; set; } = string.Empty; - - /// Provider metadata supplied by the host. - [JsonPropertyName("info")] - public JsonElement Info { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Board entry count, when available. + [JsonPropertyName("count")] + public long? Count { get; set; } } -/// Internal canvas provider unregistration parameters. +/// Session ID whose board entry count should be returned. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasProviderUnregisterRequest +internal sealed class SessionsGetBoardEntryCountRequest { - /// Connection identifier to unregister. - [JsonPropertyName("connectionId")] - public string ConnectionId { get; set; } = string.Empty; - - /// Target session identifier. + /// Session ID whose board entry count should be returned. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Machine-readable workflow run failure. -/// Polymorphic base type discriminated by type. +/// State of the runtime-managed remote-control singleton. +/// Polymorphic base type discriminated by state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", + TypeDiscriminatorPropertyName = "state", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowLimitReached), "workflow_limit_reached")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowResumeDeclined), "workflow_resume_declined")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowDurableFailure), "workflow_durable_failure")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowAccountingIncomplete), "workflow_accounting_incomplete")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowProviderDisconnected), "workflow_provider_disconnected")] -public partial class WorkflowRunFailure +[JsonDerivedType(typeof(RemoteControlStatusOff), "off")] +[JsonDerivedType(typeof(RemoteControlStatusConnecting), "connecting")] +[JsonDerivedType(typeof(RemoteControlStatusActive), "active")] +[JsonDerivedType(typeof(RemoteControlStatusError), "error")] +public partial class RemoteControlStatus { /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + [JsonPropertyName("state")] + public virtual string State { get; set; } = string.Empty; } -/// The workflow_limit_reached variant of . +/// Remote control is not connected. +/// The off variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowLimitReached : WorkflowRunFailure +public partial class RemoteControlStatusOff : RemoteControlStatus { /// [JsonIgnore] - public override string Type => "workflow_limit_reached"; - - /// Resource ceiling that stopped the run. - [JsonPropertyName("kind")] - public required WorkflowRunFailureKind Kind { get; set; } - - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } - - /// Suggested larger ceiling when the runtime can derive one safely. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("suggestedValue")] - public double? SuggestedValue { get; set; } - - /// Approved effective ceiling that was reached. - [JsonPropertyName("value")] - public required double Value { get; set; } + public override string State => "off"; } -/// The workflow_resume_declined variant of . +/// Remote control is in the middle of initial setup. +/// The connecting variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowResumeDeclined : WorkflowRunFailure +public partial class RemoteControlStatusConnecting : RemoteControlStatus { /// [JsonIgnore] - public override string Type => "workflow_resume_declined"; - - /// Human-readable reason the resume did not proceed. - [JsonPropertyName("reason")] - public required string Reason { get; set; } + public override string State => "connecting"; - /// Workflow run identifier whose changed limits were declined. - [JsonPropertyName("runId")] - public required string RunId { get; set; } + /// Session id the connection is attaching to. + [JsonPropertyName("attachedSessionId")] + public required string AttachedSessionId { get; set; } } -/// The workflow_durable_failure variant of . +/// Remote control is connected to a local session. +/// The active variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowDurableFailure : WorkflowRunFailure +public partial class RemoteControlStatusActive : RemoteControlStatus { /// [JsonIgnore] - public override string Type => "workflow_durable_failure"; - - /// Stable failure code. - [JsonPropertyName("code")] - public required string Code { get; set; } - - /// Execution-critical durable operation that failed. - [JsonPropertyName("operation")] - public required WorkflowDurableOperation Operation { get; set; } + public override string State => "active"; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } -} + /// Session id remote control is pointed at. + [JsonPropertyName("attachedSessionId")] + public required string AttachedSessionId { get; set; } -/// The run stopped because its usage accounting could not be completed. -/// The workflow_accounting_incomplete variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowAccountingIncomplete : WorkflowRunFailure -{ - /// - [JsonIgnore] - public override string Type => "workflow_accounting_incomplete"; + /// True while a read-only/session-sync export is deferred, awaiting the first `user.message` before its MC session exists. Marked internal: this field is excluded from the public SDK surface and is populated only on the CLI in-process path. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("awaitingFirstMessage")] + internal bool? AwaitingFirstMessage { get; set; } - /// Confirmed usage in nano-AIU, representing the floor of what the run spent. - [JsonPropertyName("drainedNanoAiu")] - public required long DrainedNanoAiu { get; set; } + /// MC frontend URL for this session, when known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("frontendUrl")] + public string? FrontendUrl { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } + /// Whether the MC session may steer this session. + [JsonPropertyName("isSteerable")] + public required bool IsSteerable { get; set; } } -/// The extension that owns the workflow disconnected while the run was executing, so the host halted it. The run's journaled subagent results are preserved so a resume can reuse them. -/// The workflow_provider_disconnected variant of . +/// The last setup attempt failed. The singleton is otherwise off. +/// The error variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowProviderDisconnected : WorkflowRunFailure +public partial class RemoteControlStatusError : RemoteControlStatus { /// [JsonIgnore] - public override string Type => "workflow_provider_disconnected"; + public override string State => "error"; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } -} + /// Session id the failing setup attempt targeted, when known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("attachedSessionId")] + public string? AttachedSessionId { get; set; } -/// Durable metadata describing who initiated a workflow pause. -/// Polymorphic base type discriminated by type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(WorkflowPauseInfoUser), "user")] -[JsonDerivedType(typeof(WorkflowPauseInfoCheckpoint), "checkpoint")] -public partial class WorkflowPauseInfo -{ - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + /// Human-readable error message from the last setup attempt. + [JsonPropertyName("error")] + public required string Error { get; set; } } - -/// The user variant of . +/// Wrapper for the singleton's current status. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowPauseInfoUser : WorkflowPauseInfo +public sealed class RemoteControlStatusResult { - /// - [JsonIgnore] - public override string Type => "user"; + /// State of the runtime-managed remote-control singleton. + [JsonPropertyName("status")] + public RemoteControlStatus Status { get => field ??= new(); set; } } -/// The checkpoint variant of . +/// Reattach to an existing MC session without creating a new one. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowPauseInfoCheckpoint : WorkflowPauseInfo +public sealed class RemoteControlConfigExistingMcSession { - /// - [JsonIgnore] - public override string Type => "checkpoint"; + /// Existing MC session ID to reattach to. + [JsonPropertyName("mcSessionId")] + public string McSessionId { get; set; } = string.Empty; - /// Stable author-defined checkpoint key that initiated the pause. - [JsonPropertyName("key")] - public required string Key { get; set; } + /// Existing MC task ID for the reattached session. + [JsonPropertyName("mcTaskId")] + public string McTaskId { get; set; } = string.Empty; } -/// Complete current or terminal workflow run envelope. +/// Configuration for the runtime-managed remote-control singleton. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunResult +public sealed class RemoteControlConfig { - /// One-based execution attempt represented by this envelope. Absent before the first attempt starts or when returned by an older runtime. - [JsonPropertyName("attempt")] - public long? Attempt { get; set; } - - /// Error message for an errored run. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Machine-readable failure details for a halted or errored run. - [JsonPropertyName("failure")] - public WorkflowRunFailure? Failure { get; set; } - - /// Structured pause initiator metadata for a paused attempt. - [JsonPropertyName("pauseInfo")] - public WorkflowPauseInfo? PauseInfo { get; set; } + /// Reattach to an existing MC session without creating a new one. + [JsonPropertyName("existingMcSession")] + public RemoteControlConfigExistingMcSession? ExistingMcSession { get; set; } - /// Reason for a halted or cancelled run. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Whether the user explicitly requested remote (vs. implicit session-sync). Controls warning surfacing for missing-repo cases. + [JsonPropertyName("explicit")] + public bool Explicit { get; set; } - /// Completed workflow result. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + /// Whether remote export should be enabled. + [JsonPropertyName("remote")] + public bool Remote { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// When true, suppresses timeline messages on successful setup. + [JsonPropertyName("silent")] + public bool Silent { get; set; } - /// Partial journal and progress snapshot for a halted, cancelled, or errored run. - [JsonPropertyName("snapshot")] - public JsonElement? Snapshot { get; set; } + /// Whether the MC session may steer the local session (write mode). + [JsonPropertyName("steerable")] + public bool Steerable { get; set; } - /// Current or terminal workflow run status. - [JsonPropertyName("status")] - public WorkflowRunStatus Status { get; set; } + /// Existing Mission Control task ID to attach the exported session to. + [JsonPropertyName("taskId")] + public string? TaskId { get; set; } } -/// Wire-only per-invocation workflow resource ceiling overrides. +/// Parameters for attaching the remote-control singleton to a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunLimits +internal sealed class SessionsStartRemoteControlRequest { - /// Maximum AI credits consumed by workflow subagents and their descendants. The post-paid ceiling is soft: parallel turns can settle beyond it before the run stops. - [JsonPropertyName("maxAiCredits")] - public double? MaxAiCredits { get; set; } - - /// Maximum number of workflow subagents that may run concurrently. - [JsonPropertyName("maxConcurrentSubagents")] - public long? MaxConcurrentSubagents { get; set; } - - /// Maximum total number of workflow subagents that may be admitted. - [JsonPropertyName("maxTotalSubagents")] - public long? MaxTotalSubagents { get; set; } + /// Configuration for the runtime-managed remote-control singleton. + [JsonPropertyName("config")] + public RemoteControlConfig Config { get => field ??= new(); set; } - /// Maximum accumulated active-execution time in seconds. Active execution includes the entire extension body, subprocess waits, queued-agent waits, and sleeps; time between resumed attempts is not counted. - [JsonPropertyName("timeoutSeconds")] - public double? TimeoutSeconds { get; set; } + /// Local session id to attach remote control to. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Options controlling workflow invocation. +/// Outcome of a transferRemoteControl call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunOptions +public sealed class RemoteControlTransferResult { - /// Per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } - - /// Whether to emit workflow phase names to the session transcript. - [JsonPropertyName("logPhaseNames")] - public bool? LogPhaseNames { get; set; } - - /// Whether to notify the originating session when the workflow completes. - [JsonPropertyName("notifyOnComplete")] - public bool? NotifyOnComplete { get; set; } + /// State of the runtime-managed remote-control singleton. + [JsonPropertyName("status")] + public RemoteControlStatus Status { get => field ??= new(); set; } - /// Run identifier whose journal and progress should seed this resumed run. - [JsonPropertyName("resumeFromRunId")] - public string? ResumeFromRunId { get; set; } + /// Whether the rebinding actually happened. + [JsonPropertyName("transferred")] + public bool Transferred { get; set; } } -/// Parameters for invoking a registered workflow. +/// Parameters for atomically rebinding the remote-control singleton. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowRunRequest +internal sealed class SessionsTransferRemoteControlRequest { - /// Workflow input value. - [JsonPropertyName("args")] - public JsonElement Args { get; set; } - - /// Registered workflow name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Workflow invocation options. - [JsonPropertyName("options")] - public WorkflowRunOptions? Options { get; set; } + /// When provided, the transfer is rejected unless the singleton currently points at this session id (compare-and-swap semantics to avoid clobbering newer state). + [JsonPropertyName("expectedFromSessionId")] + public string? ExpectedFromSessionId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Local session id to point remote control at. + [JsonPropertyName("toSessionId")] + public string ToSessionId { get; set; } = string.Empty; } -/// Resolved persisted workflow identity and resumed run envelope. +/// Patch for the singleton's steering state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowResumeResult +internal sealed class SessionsSetRemoteControlSteeringRequest { - /// Terminal resumed run envelope. - [JsonPropertyName("run")] - public WorkflowRunResult Run { get => field ??= new(); set; } - - /// Persisted workflow name resolved for the resumed run. - [JsonPropertyName("workflowName")] - public string WorkflowName { get; set; } = string.Empty; + /// Target steering state. Today only `true` is actionable on the underlying exporter; `false` is reserved for future use. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } } -/// Parameters for resuming a workflow run from its persisted identity. +/// Outcome of a stopRemoteControl call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowResumeRequest +public sealed class RemoteControlStopResult { - /// Optional per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } - - /// Whether to emit workflow phase names to the session transcript. - [JsonPropertyName("logPhaseNames")] - public bool? LogPhaseNames { get; set; } - - /// Whether to notify the originating session when the workflow completes. - [JsonPropertyName("notifyOnComplete")] - public bool? NotifyOnComplete { get; set; } - - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// State of the runtime-managed remote-control singleton. + [JsonPropertyName("status")] + public RemoteControlStatus Status { get => field ??= new(); set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the singleton was actually torn down by this call. + [JsonPropertyName("stopped")] + public bool Stopped { get; set; } } -/// Options for an internal tool-originated workflow invocation. +/// RPC data type for SessionsStopRemoteControl operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowToolRunOptions +internal sealed class SessionsStopRemoteControlRequest { - /// Per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } + /// When provided, the stop is rejected unless the singleton currently points at this session id (compare-and-swap semantics). + [JsonPropertyName("expectedSessionId")] + public string? ExpectedSessionId { get; set; } - /// Run identifier whose journal and progress should seed this resumed run. - [JsonPropertyName("resumeFromRunId")] - public string? ResumeFromRunId { get; set; } + /// When true, the singleton is unconditionally torn down regardless of `expectedSessionId`. Use during shutdown or explicit `/remote off`. + [JsonPropertyName("force")] + public bool? Force { get; set; } } -/// Internal parameters for invoking a registered workflow from a tool. +/// Params to attach or detach an in-process ExtensionController delegate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowToolRunRequest +internal sealed class ConfigureSessionExtensionsParams { - /// Workflow input value. - [JsonPropertyName("args")] - public JsonElement Args { get; set; } - - /// Registered workflow name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Tool-originated workflow invocation options. - [JsonPropertyName("options")] - public WorkflowToolRunOptions? Options { get; set; } - - /// Target session identifier. + /// Session to attach the extension controller delegate to. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; +} - /// Opaque identifier of the originating tool call. - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } +/// Outcome of an agentRegistry.spawn call. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawned), "spawned")] +[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawnError), "spawn-error")] +[JsonDerivedType(typeof(AgentRegistrySpawnResultRegistryTimeout), "registry-timeout")] +[JsonDerivedType(typeof(AgentRegistrySpawnResultValidationError), "validation-error")] +public partial class AgentRegistrySpawnResult +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Internal parameters for resuming a workflow run from a tool. + +/// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowToolResumeRequest +public sealed class AgentRegistryLiveTargetEntry { - /// Optional per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } + /// Kind of attention required when status === "attention". Meaningful only when status === "attention". + [JsonPropertyName("attentionKind")] + public AgentRegistryLiveTargetEntryAttentionKind? AttentionKind { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Git branch of the session (when known). + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Target session identifier. + /// Copilot CLI version that wrote the entry. + [JsonPropertyName("copilotVersion")] + public string CopilotVersion { get; set; } = string.Empty; + + /// Working directory of the session (when known). + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } + + /// Bind host for the entry's JSON-RPC server. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// Process kind tag for the registry entry. + [JsonPropertyName("kind")] + public AgentRegistryLiveTargetEntryKind Kind { get; set; } + + /// Wall-clock milliseconds since the watcher last observed this entry (heartbeat freshness). + [JsonPropertyName("lastSeenMs")] + public long LastSeenMs { get; set; } + + /// How the most recent turn ended (clean vs aborted). Lets the renderer distinguish done from done_cancelled. + [JsonPropertyName("lastTerminalEvent")] + public AgentRegistryLiveTargetEntryLastTerminalEvent? LastTerminalEvent { get; set; } + + /// Model identifier currently selected for the session. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Operating-system pid of the process owning this entry. + [JsonPropertyName("pid")] + public long Pid { get; set; } + + /// TCP port the entry's JSON-RPC server is listening on. + [JsonPropertyName("port")] + public long Port { get; set; } + + /// Registry entry schema version (1 = ui-server, 2 = managed-server). + [JsonPropertyName("schemaVersion")] + public long SchemaVersion { get; set; } + + /// Session ID of the foreground session for this entry. [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public string? SessionId { get; set; } - /// Opaque identifier of the originating tool call. - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + /// Friendly session name (when set). + [JsonPropertyName("sessionName")] + public string? SessionName { get; set; } + + /// ISO 8601 timestamp captured at registration. + [JsonPropertyName("startedAt")] + public string StartedAt { get; set; } = string.Empty; + + /// Coarse lifecycle status of the foreground session. + [JsonPropertyName("status")] + public AgentRegistryLiveTargetEntryStatus? Status { get; set; } + + /// Monotonic per-publisher revision counter incremented on every status update. Lets watchers detect transient flips. + [JsonPropertyName("statusRevision")] + public long? StatusRevision { get; set; } + + /// Connection token (null when the target is unauthenticated). + [JsonInclude] + [JsonPropertyName("token")] + internal string? Token { get; set; } } -/// Parameters for retrieving a workflow run. +/// Canonical process-log discovery outcome; populated from spawnLiveTarget. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowGetRunRequest +public sealed class AgentRegistryLogCapture { - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Whether a canonical process log was discovered for this managed spawn. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Why no canonical process log could be opened for this managed spawn (set only when enabled is false). + [JsonPropertyName("openError")] + public string? OpenError { get; set; } + + /// Categorized reason no canonical process log could be opened (set only when enabled is false). + [JsonPropertyName("openErrorReason")] + public AgentRegistryLogCaptureOpenErrorReason? OpenErrorReason { get; set; } + + /// Absolute path to the managed spawn's process-<timestamp>-<pid>.log file (only set when enabled). + [JsonPropertyName("path")] + public string? Path { get; set; } } -/// Declared or approved workflow resource ceilings. +/// Managed-server child was spawned and registered successfully. +/// The spawned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowDeclaredLimits +public partial class AgentRegistrySpawnResultSpawned : AgentRegistrySpawnResult { - /// Maximum AI credits consumed by subagents and descendants. - [JsonPropertyName("maxAiCredits")] - public double? MaxAiCredits { get; set; } + /// + [JsonIgnore] + public override string Kind => "spawned"; - /// Maximum concurrently active subagents. - [JsonPropertyName("maxConcurrentSubagents")] - public long? MaxConcurrentSubagents { get; set; } + /// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). + [JsonPropertyName("entry")] + public required AgentRegistryLiveTargetEntry Entry { get; set; } - /// Maximum total subagents spawned by the run. - [JsonPropertyName("maxTotalSubagents")] - public long? MaxTotalSubagents { get; set; } + /// If the delegate attempted to send the initial prompt and failed, the categorized error message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("initialPromptError")] + public string? InitialPromptError { get; set; } - /// Maximum accumulated active execution time in seconds. - [JsonPropertyName("timeoutSeconds")] - public double? TimeoutSeconds { get; set; } + /// Whether the delegate already sent the initial prompt. Always omitted in the current wiring: the controller sends the prompt post-attach via the standard LocalRpcSession.send path. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("initialPromptSent")] + public bool? InitialPromptSent { get; set; } + + /// Per-spawn log-capture outcome; populated from spawnLiveTarget. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("logCapture")] + public AgentRegistryLogCapture? LogCapture { get; set; } } -/// Durable workflow resource consumption. +/// `child_process.spawn` itself failed before the child entered the registry. +/// The spawn-error variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunConsumed +public partial class AgentRegistrySpawnResultSpawnError : AgentRegistrySpawnResult { - /// Accumulated active execution time in milliseconds. - [JsonPropertyName("activeMs")] - public long ActiveMs { get; set; } + /// + [JsonIgnore] + public override string Kind => "spawn-error"; - /// AI usage consumed by the run in nano-AIU. - [JsonPropertyName("nanoAiu")] - public long NanoAiu { get; set; } + /// Underlying errno code (e.g. ENOENT, EACCES) when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("code")] + public string? Code { get; set; } - /// Total subagents spawned by the run. - [JsonPropertyName("subagents")] - public long Subagents { get; set; } + /// Human-readable error message. + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Current workflow phase identity. +/// Spawn succeeded but the child did not publish a matching managed-server entry within the timeout. +/// The registry-timeout variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowCurrentPhase +public partial class AgentRegistrySpawnResultRegistryTimeout : AgentRegistrySpawnResult { - /// Current phase identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "registry-timeout"; - /// Zero-based declared phase ordinal, or null for an undeclared phase. - [JsonPropertyName("ordinal")] - public long? Ordinal { get; set; } + /// Process ID of the orphaned child (so the caller can offer 'kill the pid' guidance). + [JsonPropertyName("childPid")] + public required long ChildPid { get; set; } + + /// Per-spawn log-capture outcome; populated from spawnLiveTarget. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("logCapture")] + public AgentRegistryLogCapture? LogCapture { get; set; } } -/// Prompt-safe terminal workflow outcome. +/// Synchronous pre-validation rejected the spawn request. +/// The validation-error variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunTerminal +public partial class AgentRegistrySpawnResultValidationError : AgentRegistrySpawnResult { - /// Human-readable terminal error. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// + [JsonIgnore] + public override string Kind => "validation-error"; - /// Machine-readable terminal failure. - [JsonPropertyName("failure")] - public WorkflowRunFailure? Failure { get; set; } + /// Which parameter field was invalid. Omitted when the rejection is not field-specific. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("field")] + public AgentRegistrySpawnValidationErrorField? Field { get; set; } - /// Pause initiator metadata, or null when the run did not pause. - [JsonPropertyName("pauseInfo")] - public WorkflowPauseInfo? PauseInfo { get; set; } + /// Human-readable explanation; safe to surface in the UI banner. Never logged to unrestricted telemetry. + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Human-readable terminal reason. + /// Categorized reason for the rejection. Low-cardinality enum so telemetry can aggregate by reason without leaking raw paths or agent/model names. [JsonPropertyName("reason")] - public string? Reason { get; set; } - - /// Prompt-safe preview of the completed result. - [JsonPropertyName("resultPreview")] - public string? ResultPreview { get; set; } + public required AgentRegistrySpawnValidationErrorReason Reason { get; set; } } -/// Durable workflow run summary with read-time live overlays. +/// Inputs to spawn a managed-server child via the controller's spawn delegate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunSummary +internal sealed class AgentRegistrySpawnRequest { - /// Epoch milliseconds when the current active segment started, or null while inactive. - [JsonPropertyName("activeSegmentStartedAt")] - public long? ActiveSegmentStartedAt { get; set; } - - /// Approved effective resource ceilings, or null until approved. - [JsonPropertyName("approved")] - public WorkflowDeclaredLimits? Approved { get; set; } - - /// Whether the durable run state currently passes runtime resume eligibility checks. - [JsonPropertyName("canResume")] - public bool CanResume { get; set; } - - /// Epoch milliseconds when the run completed, or null while nonterminal. - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } + /// Custom or built-in agent name (e.g. 'explore'). When omitted, the child uses its own default. + [JsonPropertyName("agentName")] + public string? AgentName { get; set; } - /// Durable resource consumption. - [JsonPropertyName("consumed")] - public WorkflowRunConsumed Consumed { get => field ??= new(); set; } + /// Working directory for the spawned child (must be an existing directory). + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// Epoch milliseconds when the run was created. - [JsonPropertyName("createdAt")] - public long CreatedAt { get; set; } + /// Optional first user message. Forwarded to the caller (the CLI's spawn wrapper sends it post-attach via the standard LocalRpcSession.send path). + [JsonPropertyName("initialPrompt")] + public string? InitialPrompt { get; set; } - /// Current phase identity, or null before any phase is entered. - [JsonPropertyName("currentPhase")] - public WorkflowCurrentPhase? CurrentPhase { get; set; } + /// Model identifier to apply to the new session. + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Resource ceilings declared by the workflow. - [JsonPropertyName("declaredLimits")] - public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } + /// Friendly session name. Must satisfy validateSessionName: non-empty, no leading/trailing whitespace, <=100 chars, no control chars, no double quotes. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Number of phases declared by the workflow. - [JsonPropertyName("declaredPhaseCount")] - public long DeclaredPhaseCount { get; set; } + /// Permission posture for the new session. 'yolo' requires the controller-local session to currently be in allow-all mode. + [JsonPropertyName("permissionMode")] + public AgentRegistrySpawnPermissionMode? PermissionMode { get; set; } +} - /// Human-readable workflow description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; +/// Feature availability. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDiscoveryCapabilities +{ + /// API version. + [JsonPropertyName("apiVersion")] + public long ApiVersion { get; set; } - /// Number of direct workflow agents currently live. - [JsonPropertyName("liveAgentCount")] - public long LiveAgentCount { get; set; } + /// Availability. + [JsonPropertyName("availability")] + public ConnectorDiscoveryAvailability Availability { get; set; } - /// Epoch milliseconds when this live-overlay snapshot was observed. - [JsonPropertyName("observedAt")] - public long ObservedAt { get; set; } + /// Whether results are cached. + [JsonPropertyName("conditionalCache")] + public bool ConditionalCache { get; set; } - /// Monotonic durable run revision. - [JsonPropertyName("revision")] - public long Revision { get; set; } + /// Whether accounts are selected by opaque ID. + [JsonPropertyName("opaqueAccountSelection")] + public bool OpaqueAccountSelection { get; set; } +} - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; +/// Account metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDiscoveryAuthInfo +{ + /// Host. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Epoch milliseconds when execution first started, or null before start. - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } + /// Login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Current workflow run status. - [JsonPropertyName("status")] - public WorkflowRunStatus Status { get; set; } + /// Authentication type. + [JsonPropertyName("type")] + public AuthInfoType Type { get; set; } +} - /// Terminal run outcome, or null while nonterminal. - [JsonPropertyName("terminal")] - public WorkflowRunTerminal? Terminal { get; set; } +/// Eligible account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDiscoveryAccount +{ + /// Opaque account ID. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; - /// Total direct workflow agents spawned across all attempts. - [JsonPropertyName("totalSpawnedAgentCount")] - public long TotalSpawnedAgentCount { get; set; } + /// Account metadata. + [JsonPropertyName("authInfo")] + public ConnectorDiscoveryAuthInfo AuthInfo { get => field ??= new(); set; } +} - /// Epoch milliseconds when the durable run was last updated. - [JsonPropertyName("updatedAt")] - public long UpdatedAt { get; set; } +/// Eligible accounts. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDiscoveryAccountList +{ + /// Eligible accounts. + [JsonPropertyName("accounts")] + public IList Accounts { get => field ??= []; set; } - /// Registered workflow name. - [JsonPropertyName("workflowName")] - public string WorkflowName { get; set; } = string.Empty; + /// Availability. + [JsonPropertyName("availability")] + public ConnectorDiscoveryAvailability Availability { get; set; } } -/// A page of workflow runs in durable creation order. +/// Entry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowListRunsResult +public sealed class ConnectorDiscoveryCatalogEntry { - /// Whether terminal runs newer than this page exist. - [JsonPropertyName("hasMoreNewer")] - public bool? HasMoreNewer { get; set; } + /// Description. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Newest terminal-run cursor in this page, or null when the terminal window is empty. - [JsonPropertyName("newestSeq")] - public long? NewestSeq { get; set; } + /// Display name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Oldest terminal-run cursor in this page, or null when the terminal window is empty. - [JsonPropertyName("oldestSeq")] - public long? OldestSeq { get; set; } + /// Logo. + [JsonPropertyName("logo")] + public string? Logo { get; set; } - /// Number of terminal runs older than this page. - [JsonPropertyName("omittedOlder")] - public long? OmittedOlder { get; set; } + /// Name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Workflow run summaries in durable creation order. - [JsonPropertyName("runs")] - public IList Runs { get => field ??= []; set; } + /// Release tag. + [JsonPropertyName("releaseTag")] + public string? ReleaseTag { get; set; } + + /// Status. + [JsonPropertyName("status")] + public ConnectorCatalogStatus Status { get; set; } + + /// Tier. + [JsonPropertyName("tier")] + public string? Tier { get; set; } } -/// Parameters for paging workflow runs. +/// Entries for the selected account. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowListRunsRequest +public sealed class ConnectorDiscoveryCatalogResult { - /// Exclusive forward cursor. - [JsonPropertyName("afterSeq")] - public long? AfterSeq { get; set; } + /// Opaque account ID. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; - /// Exclusive backward cursor. - [JsonPropertyName("beforeSeq")] - public long? BeforeSeq { get; set; } + /// Entries. + [JsonPropertyName("connectors")] + public IList Connectors { get => field ??= []; set; } - /// Maximum terminal runs to return. Defaults to 200 and is capped at 500. - [JsonPropertyName("limit")] - public int? Limit { get; set; } + /// Refresh time in Unix epoch milliseconds. + [JsonPropertyName("refreshedAtMs")] + public long RefreshedAtMs { get; set; } + + /// Revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } +} + +/// Selected account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorDiscoveryAccountRequest +{ + /// Opaque account ID. + [RegularExpression("^\\S+$")] + [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)] + [MaxLength(2048)] + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSuspendRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Prompt-safe durable identity and live status for a direct workflow agent. +/// Result of sending a user message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAgentSummary +public sealed class SendResult { - /// Accumulated active agent time in milliseconds. - [JsonPropertyName("activeMs")] - public long ActiveMs { get; set; } + /// Unique identifier assigned to the message. + [JsonPropertyName("messageId")] + public string MessageId { get; set; } = string.Empty; +} - /// Prompt-safe live activity text. - [JsonPropertyName("activity")] - public string? Activity { get; set; } +/// Provider-native structured output format. JSON Schema is forwarded without rewriting or validating the schema or the generated output. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(ResponseFormatJsonSchema), "json_schema")] +public partial class ResponseFormat +{ + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; +} - /// Stable direct-agent identifier. - [JsonPropertyName("agentId")] - public string AgentId { get; set; } = string.Empty; - /// Registered agent type. - [JsonPropertyName("agentType")] - public string AgentType { get; set; } = string.Empty; +/// A JSON Schema output contract. OpenAI receives the name, description, schema and strict setting; Anthropic receives the schema in output_config.format and always uses its native strict enforcement. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class JsonSchemaResponseFormat +{ + /// Optional description passed to OpenAI providers. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Epoch milliseconds when the agent completed. - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } + /// Name of the output schema, subject to the provider's naming restrictions. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Friendly, non-unique name intended for display. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } + /// JSON Schema passed unchanged to the inference provider. Schemas larger than 32 MiB when JSON-encoded are rejected before admission, using the runtime's existing request-size ceiling. This is not a guarantee that the entire model request fits. Supported keywords and schema restrictions are determined by the provider. + [JsonPropertyName("schema")] + public JsonElement Schema { get; set; } - /// Friendly, non-unique name intended for display. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// Optional strict enforcement setting for OpenAI providers. Omitted uses the provider default. Anthropic always enforces its supported schema subset. + [JsonPropertyName("strict")] + public bool? Strict { get; set; } +} - /// Phase identifier active when the agent was launched, or null. - [JsonPropertyName("phaseId")] - public string? PhaseId { get; set; } +/// The json_schema variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ResponseFormatJsonSchema : ResponseFormat +{ + /// + [JsonIgnore] + public override string Type => "json_schema"; - /// Model requested when the agent was launched. - [JsonPropertyName("requestedModel")] - public string? RequestedModel { get; set; } + /// JSON Schema and provider options for the turn's output. + [JsonPropertyName("jsonSchema")] + public required JsonSchemaResponseFormat JsonSchema { get; set; } +} - /// Concrete model resolved for the agent. - [JsonPropertyName("resolvedModel")] - public string? ResolvedModel { get; set; } +/// Parameters for sending a user message to the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SendRequest +{ + /// The UI mode the agent was in when this message was sent. Defaults to the session's current mode. + [JsonPropertyName("agentMode")] + public SendAgentMode? AgentMode { get; set; } - /// Owning workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } - /// Epoch milliseconds when the agent started. - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } - - /// Current durable or live agent status. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; - - /// Tool-call identifier that launched the agent. - [JsonPropertyName("toolCallId")] - public string ToolCallId { get; set; } = string.Empty; -} - -/// Durable lifecycle and timing for one workflow phase. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowPhaseObservation -{ - /// Completed active time accumulated by this phase in milliseconds. - [JsonPropertyName("accumulatedActiveMs")] - public long AccumulatedActiveMs { get; set; } + /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. + [JsonPropertyName("billable")] + public bool? Billable { get; set; } - /// Epoch milliseconds when this phase completed; for a skipped phase, the synthetic skip timestamp (equal to `startedAt`). - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } + /// If provided, this is shown in the timeline instead of `prompt`. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// Current live active time for this phase in milliseconds. - [JsonPropertyName("currentActiveMs")] - public long CurrentActiveMs { get; set; } + /// How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. + [JsonPropertyName("mode")] + public SendMode? Mode { get; set; } - /// Optional human-readable phase detail. - [JsonPropertyName("detail")] - public string? Detail { get; set; } + /// If true, adds the message to the front of the queue instead of the end. + [JsonPropertyName("prepend")] + public bool? Prepend { get; set; } - /// Number of times execution entered this phase. - [JsonPropertyName("entryCount")] - public long EntryCount { get; set; } + /// The user message text. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Phase identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// 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. + [JsonPropertyName("requestHeaders")] + public IDictionary? RequestHeaders { get; set; } - /// Most recent run attempt that entered this phase, or `0` if the phase has never been entered. - [JsonPropertyName("lastEnteredRunAttempt")] - public long LastEnteredRunAttempt { get; set; } + /// 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. + [JsonPropertyName("requiredTool")] + public string? RequiredTool { get; set; } - /// Direct agents in this phase that are currently live. - [JsonPropertyName("liveAgentCount")] - public long LiveAgentCount { get; set; } + /// Provider-native output format for this turn, including all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. + [JsonPropertyName("responseFormat")] + public ResponseFormat? ResponseFormat { get; set; } - /// Zero-based declared phase ordinal, or null for an undeclared phase. - [JsonPropertyName("ordinal")] - public long? Ordinal { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Epoch milliseconds when this phase first started; for a skipped phase, the synthetic skip timestamp (equal to `completedAt`). - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } + /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. + [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] + [JsonInclude] + [JsonPropertyName("source")] + internal string? Source { get; set; } - /// Derived lifecycle state of the phase. - [JsonPropertyName("status")] - public WorkflowPhaseStatus Status { get; set; } + /// W3C Trace Context traceparent header for distributed tracing of this agent turn. + [JsonPropertyName("traceparent")] + public string? Traceparent { get; set; } - /// Human-readable phase title. - [JsonPropertyName("title")] - public string Title { get; set; } = string.Empty; + /// W3C Trace Context tracestate header for distributed tracing. + [JsonPropertyName("tracestate")] + public string? Tracestate { get; set; } - /// Total direct agents associated with this phase. - [JsonPropertyName("totalAgentCount")] - public long TotalAgentCount { get; set; } + /// If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } } -/// One durable workflow progress record. +/// Result of sending zero or more user messages. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowProgressLine +public sealed class SendMessagesResult { - /// Resume attempt that emitted this record. - [JsonPropertyName("attempt")] - public long Attempt { get; set; } - - /// Progress record kind. - [JsonPropertyName("kind")] - public WorkflowLogLineKind Kind { get; set; } - - /// Phase active when the record was emitted, or null before any phase. - [JsonPropertyName("phaseId")] - public string? PhaseId { get; set; } - - /// Epoch milliseconds when the record was persisted. - [JsonPropertyName("recordedAt")] - public long RecordedAt { get; set; } - - /// Global monotonic sequence number within the run. - [JsonPropertyName("seq")] - public long Seq { get; set; } - - /// Prompt-safe progress text. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; + /// Unique identifiers assigned to the messages, one per provided message in order. For a batch that starts a run, assistant messages use the final ID as originatingMessageId throughout that run, including tool iterations and stop-hook corrections. Immediate steering does not replace the active run's origin. Empty when no messages were provided; that run has no originatingMessageId. + [JsonPropertyName("messageIds")] + public IList MessageIds { get => field ??= []; set; } } -/// A bidirectional page of workflow progress. +/// A single user message to append to the session as part of a `session.sendMessages` turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowProgressPage +public sealed class SendMessageItem { - /// Whether progress records newer than this page exist. - [JsonPropertyName("hasMoreNewer")] - public bool HasMoreNewer { get; set; } + /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with this message. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } - /// Whether progress records older than this page exist. - [JsonPropertyName("hasMoreOlder")] - public bool HasMoreOlder { get; set; } + /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. + [JsonInclude] + [JsonPropertyName("billable")] + internal bool? Billable { get; set; } - /// Newest sequence number in this page, or null when empty. - [JsonPropertyName("newestSeq")] - public long? NewestSeq { get; set; } + /// If provided, this is shown in the timeline instead of `prompt`. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// Oldest sequence number in this page, or null when empty. - [JsonPropertyName("oldestSeq")] - public long? OldestSeq { get; set; } + /// The user message text. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Progress records in sequence order. - [JsonPropertyName("records")] - public IList Records { get => field ??= []; set; } + /// 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. + [JsonPropertyName("requiredTool")] + public string? RequiredTool { get; set; } - /// Run revision reflected by this page. - [JsonPropertyName("revision")] - public long Revision { get; set; } + /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. + [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] + [JsonInclude] + [JsonPropertyName("source")] + internal string? Source { get; set; } } -/// Full workflow run observability detail. +/// Parameters for sending zero or more user messages to the session in a single turn. Remote-backed (Mission Control) sessions do not support this method and will return an error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunDetail +internal sealed class SendMessagesRequest { - /// Epoch milliseconds when the current active segment started, or null while inactive. - [JsonPropertyName("activeSegmentStartedAt")] - public long? ActiveSegmentStartedAt { get; set; } - - /// Durable identities and live statuses for direct workflow agents. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } - - /// Approved effective resource ceilings, or null until approved. - [JsonPropertyName("approved")] - public WorkflowDeclaredLimits? Approved { get; set; } - - /// Whether the durable run state currently passes runtime resume eligibility checks. - [JsonPropertyName("canResume")] - public bool CanResume { get; set; } - - /// Epoch milliseconds when the run completed, or null while nonterminal. - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } - - /// Durable resource consumption. - [JsonPropertyName("consumed")] - public WorkflowRunConsumed Consumed { get => field ??= new(); set; } - - /// Epoch milliseconds when the run was created. - [JsonPropertyName("createdAt")] - public long CreatedAt { get; set; } - - /// Current phase identity, or null before any phase is entered. - [JsonPropertyName("currentPhase")] - public WorkflowCurrentPhase? CurrentPhase { get; set; } - - /// Resource ceilings declared by the workflow. - [JsonPropertyName("declaredLimits")] - public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } - - /// Number of phases declared by the workflow. - [JsonPropertyName("declaredPhaseCount")] - public long DeclaredPhaseCount { get; set; } - - /// Human-readable workflow description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Number of direct workflow agents currently live. - [JsonPropertyName("liveAgentCount")] - public long LiveAgentCount { get; set; } - - /// Epoch milliseconds when this live-overlay snapshot was observed. - [JsonPropertyName("observedAt")] - public long ObservedAt { get; set; } - - /// Lifecycle and timing observations for each workflow phase. - [JsonPropertyName("phases")] - public IList Phases { get => field ??= []; set; } + /// The UI mode the agent was in when these messages were sent. Defaults to the session's current mode. + [JsonPropertyName("agentMode")] + public SendAgentMode? AgentMode { get; set; } - /// Bidirectional page of durable workflow progress. - [JsonPropertyName("progress")] - public WorkflowProgressPage Progress { get => field ??= new(); set; } + /// The user messages to append to the conversation, in order, before running one agent loop. When the batch starts a run, its final message is the primary initiating message; earlier messages provide context, not separate runs or replies. May be empty, in which case a single turn runs over the existing history with no new user message or originatingMessageId. + [JsonPropertyName("messages")] + public IList Messages { get => field ??= []; set; } - /// Monotonic durable run revision. - [JsonPropertyName("revision")] - public long Revision { get; set; } + /// How to deliver the messages. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. + [JsonPropertyName("mode")] + public SendMode? Mode { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// If true, adds the messages to the front of the queue instead of the end. + [JsonPropertyName("prepend")] + public bool? Prepend { get; set; } - /// Epoch milliseconds when execution first started, or null before start. - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } + /// 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. + [JsonPropertyName("requestHeaders")] + public IDictionary? RequestHeaders { get; set; } - /// Current workflow run status. - [JsonPropertyName("status")] - public WorkflowRunStatus Status { get; set; } + /// Provider-native output format for the whole turn, including an empty message batch and all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. + [JsonPropertyName("responseFormat")] + public ResponseFormat? ResponseFormat { get; set; } - /// Terminal run outcome, or null while nonterminal. - [JsonPropertyName("terminal")] - public WorkflowRunTerminal? Terminal { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Total direct workflow agents spawned across all attempts. - [JsonPropertyName("totalSpawnedAgentCount")] - public long TotalSpawnedAgentCount { get; set; } + /// W3C Trace Context traceparent header for distributed tracing of this agent turn. + [JsonPropertyName("traceparent")] + public string? Traceparent { get; set; } - /// Epoch milliseconds when the durable run was last updated. - [JsonPropertyName("updatedAt")] - public long UpdatedAt { get; set; } + /// W3C Trace Context tracestate header for distributed tracing. + [JsonPropertyName("tracestate")] + public string? Tracestate { get; set; } - /// Registered workflow name. - [JsonPropertyName("workflowName")] - public string WorkflowName { get; set; } = string.Empty; + /// If true, await completion of the agentic loop for this turn before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageIds`; the caller can rely on the agent having processed the messages before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } } -/// Parameters for paging workflow progress. +/// Internal request for sending a system notification. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowGetRunProgressRequest +internal sealed class SendSystemNotificationRequest { - /// Exclusive forward cursor. - [JsonPropertyName("afterSeq")] - public long? AfterSeq { get; set; } - - /// Exclusive backward cursor. - [JsonPropertyName("beforeSeq")] - public long? BeforeSeq { get; set; } - - /// Maximum records to return. Defaults to 200 and is capped at 500. - [JsonPropertyName("limit")] - public int? Limit { get; set; } + /// Optional structured notification kind. + [JsonPropertyName("kind")] + public JsonElement? Kind { get; set; } - /// Optional phase identifier used to scope records and cursors. - [JsonPropertyName("phaseId")] - public string? PhaseId { get; set; } + /// Notification text to deliver to the model. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Internal delivery options, including passive policy. + [JsonPropertyName("options")] + public JsonElement? Options { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Parameters for cancelling a workflow run. +/// Result of aborting the current turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowCancelRequest +public sealed class AbortResult { - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Error message if the abort failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the abort completed successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Parameters for pausing a running workflow. +/// Parameters for aborting the current turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowPauseRequest +internal sealed class AbortRequest { - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Finite reason code describing why the current turn was aborted. + [JsonPropertyName("reason")] + public AbortReason? Reason { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// RPC data type for SessionWorkflowPauseAtCheckpoint operations. +/// Result of interrupting the main agent turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkflowPauseAtCheckpointResult +public sealed class InterruptMainTurnResult { - /// Whether this execution attempt must pause or may continue. - [JsonPropertyName("action")] - public WorkflowPauseCheckpointAction Action { get; set; } + /// Whether an in-flight main agent turn was interrupted. False when the main loop was not processing. + [JsonPropertyName("interrupted")] + public bool Interrupted { get; set; } } -/// Parameters for an owned durable pause checkpoint. +/// Parameters for interrupting the main agent turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowPauseCheckpointRequest +internal sealed class InterruptMainTurnRequest { - /// Opaque token identifying the execution attempt that reached the checkpoint. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; - - /// Stable author-defined checkpoint key. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; - - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// When true, the user's queued prompts are preserved and run as the next turn once the interrupted turn unwinds; when false (the default), the queue is cleared like a plain abort. + [JsonPropertyName("flushQueued")] + public bool? FlushQueued { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Acknowledgement that a workflow request was accepted. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAckResult -{ -} - -/// One ordered workflow progress line. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowLogLine +internal sealed class SessionCancelAllBackgroundAgentsRequest { - /// Progress line kind. - [JsonPropertyName("kind")] - public WorkflowLogLineKind Kind { get; set; } - - /// Monotonic sequence number within the workflow run. - [JsonPropertyName("seq")] - public long Seq { get; set; } - - /// Progress text. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for recording workflow progress. +/// Parameters for shutting down the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowLogRequest +internal sealed class ShutdownRequest { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; - - /// Ordered progress lines to append. - [JsonPropertyName("lines")] - public IList Lines { get => field ??= []; set; } + /// Dispatch deferred sessionEnd hooks in the background with their full per-hook timeoutSec instead of awaiting them under the short shared shutdown budget. Set this when the host process keeps running after the session closes (for example the CLI's /clear), so a slow hook neither blocks the close nor is aborted. Hooks still detached when the process later exits are terminated with it. Defaults to false. + [JsonPropertyName("detachSessionEndHooks")] + public bool? DetachSessionEndHooks { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. + [JsonPropertyName("reason")] + public string? Reason { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Why the session is being shut down. Defaults to "routine" when omitted. + [JsonPropertyName("type")] + public ShutdownType? Type { get; set; } } -/// Result of one workflow-scoped subagent call. +/// Identifier of the session event that was emitted for the log message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAgentResult +public sealed class LogResult { - /// Agent result, omitted when the agent produced no result. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + /// The unique identifier of the emitted session event. + [JsonPropertyName("eventId")] + public Guid EventId { get; set; } } -/// Options for one workflow-scoped subagent call. +/// Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAgentOptions +internal sealed class LogRequest { - /// Optional built-in or custom agent name whose definition configures the subagent. - [JsonPropertyName("agent")] - public string? Agent { get; set; } + /// When true, the message is transient and not persisted to the session event log on disk. + [JsonPropertyName("ephemeral")] + public bool? Ephemeral { get; set; } - /// Optional context tier override for the subagent. - [JsonPropertyName("contextTier")] - public ContextTier? ContextTier { get; set; } + /// Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". + [JsonPropertyName("level")] + public SessionLogLevel? Level { get; set; } - /// Optional label distinguishing otherwise identical memoized agent calls. - [JsonPropertyName("label")] - public string? Label { get; set; } + /// Human-readable message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Optional model identifier for the subagent. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Optional reasoning effort override for the subagent. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// Optional actionable tip displayed alongside the message. Only honored on `level: "info"`. + [JsonPropertyName("tip")] + public string? Tip { get; set; } - /// Optional JSON Schema for structured agent output. - [JsonPropertyName("schema")] - public JsonElement? Schema { get; set; } + /// Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". + [JsonPropertyName("type")] + public string? Type { get; set; } + + /// Optional URL the user can open in their browser for more details. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// Parameters for one workflow-scoped subagent call. +/// Adapter-declared policy that tells clients whether discovery may run automatically. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowAgentRequest +public sealed class ModelProviderAutomaticDiscoveryPolicy { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; - - /// Subagent execution options. - [JsonPropertyName("opts")] - public WorkflowAgentOptions Opts { get => field ??= new(); set; } + /// Whether automatic discovery is allowed, limited to configured providers, or explicit-only. + [JsonPropertyName("mode")] + public ModelProviderAutomaticDiscoveryMode Mode { get; set; } - /// Prompt to send to the subagent. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Maximum network scope used by this adapter during discovery. + [JsonPropertyName("networkScope")] + public ModelProviderDiscoveryNetworkScope NetworkScope { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// True when discovery requires non-null caller input. Omission or null is rejected before adapter execution. When false, omitted or null input selects adapter defaults without schema validation. + [JsonPropertyName("requiresInput")] + public bool RequiresInput { get; set; } - /// Workflow run identifier that owns the subagent. - [JsonPropertyName("workflowRunId")] - public string WorkflowRunId { get; set; } = string.Empty; + /// True when the adapter must be enabled by a trusted owner, such as a trusted extension, before automatic discovery may run. + [JsonPropertyName("requiresTrust")] + public bool RequiresTrust { get; set; } } -/// Result of reading a workflow journal entry. +/// An operation supported by a model-provider adapter. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowJournalGetResult +public sealed class ModelProviderAdapterOperationDescriptor { - /// Whether the journal contained the requested key. - [JsonPropertyName("hit")] - public bool Hit { get; set; } + /// Optional self-contained JSON Schema Draft 7 for non-null discovery input. Only supported on discover. No external references are resolved. Omitted or null input selects defaults when requiresInput is false. Without a schema, the adapter validates supplied input. + [JsonPropertyName("inputSchema")] + public JsonElement? InputSchema { get; set; } - /// Cached JSON result. The hit field distinguishes a cached JSON null from a miss. - [JsonPropertyName("resultJson")] - public JsonElement? ResultJson { get; set; } + /// Supported operation name: `discover`, `getStatus`, or `models.list`. Unknown names and duplicate declarations are rejected. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Parameters for reading a workflow journal entry. +/// Contributor attribution, independent of routing identity and authorization. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowJournalGetRequest +public sealed class ModelProviderAttribution { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; - - /// Namespaced journal key. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// Human-readable contributor name, not the adapter display name. + [JsonPropertyName("ownerDisplayName")] + public string? OwnerDisplayName { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Stable contributor identifier. Required and nonblank for extension and custom sources; optional for built-in and configured sources. Does not grant authority. + [JsonPropertyName("ownerId")] + public string? OwnerId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Kind of component that supplied the adapter. Attribution does not confer authority. + [JsonPropertyName("source")] + public ModelProviderProvenanceSource Source { get; set; } } -/// Parameters for storing a workflow journal entry. +/// A normalized model-provider adapter in the session's effective catalog. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowJournalPutRequest +public sealed class ModelProviderAdapterDescriptor { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; + /// Stable opaque identity for routing to this adapter. Unique in the effective catalog, independent of live registration generations. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; - /// Namespaced journal key. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// Adapter-declared policy for passive and automatic discovery. + [JsonPropertyName("automaticDiscovery")] + public ModelProviderAutomaticDiscoveryPolicy AutomaticDiscovery { get => field ??= new(); set; } - /// JSON result to memoize. - [JsonPropertyName("resultJson")] - public JsonElement ResultJson { get; set; } + /// Human-readable provider name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Operations supported by this provider adapter. + [JsonPropertyName("operations")] + public IList Operations { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Attribution for the adapter itself. + [JsonPropertyName("provenance")] + public ModelProviderAttribution Provenance { get => field ??= new(); set; } + + /// Descriptive provider family, such as `ollama`. Different adapters may have the same family; use adapterId for routing. + [JsonPropertyName("providerKind")] + public string ProviderKind { get; set; } = string.Empty; } -/// The session's authoritative model snapshot. Auto preference fields are configuration for the virtual `auto` model and do not change the selected model identifier. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume. +/// Normalized model-provider adapter definitions available to the session, not discovered instances. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CurrentModel +public sealed class ModelProviderAdapterCatalog { - /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. - [JsonPropertyName("activatingAutoTier")] - public AutoTier? ActivatingAutoTier { get; set; } - - /// Auto preference currently committed for the session. This can remain available while another model is selected so a later switch to `auto` can reuse it. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// 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; } - - /// Latest unclaimed Auto preference waiting for a future user turn. Null means the pending request is returning to provider-default routing. - [JsonPropertyName("pendingAutoTier")] - public AutoTier? PendingAutoTier { get; set; } - - /// Captured base model to restore when leaving plan mode. Omitted outside plan mode or when no plan override has captured a base model. Persistent agent model requirements apply to this model rather than the temporary plan model. - [JsonPropertyName("planBaseModelId")] - public string? PlanBaseModelId { get; set; } - - /// Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// Available provider adapters ordered by adapterId. + [JsonPropertyName("providers")] + public IList Providers { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModelGetCurrentRequest +internal sealed class SessionProvidersGetCatalogRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// RPC data type for ModelSwitchConfirmation operations. +/// Attribution for the adapter that produced a provider row. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSwitchConfirmation +public sealed class ModelProviderProvenance { - /// Current conversation token count before switching models. - [JsonPropertyName("currentTokens")] - public double CurrentTokens { get; set; } + /// Stable opaque adapter identity from the effective catalog. Treat this as a whole identifier, not a parseable owner or kind. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; - /// Target model token limit used by the compaction preflight. - [JsonPropertyName("targetLimit")] - public double TargetLimit { get; set; } + /// Human-readable contributor name, not the adapter display name. + [JsonPropertyName("ownerDisplayName")] + public string? OwnerDisplayName { get; set; } - /// Display name of the model that requires compaction confirmation. - [JsonPropertyName("targetModelDisplayName")] - public string TargetModelDisplayName { get; set; } = string.Empty; + /// Stable contributor identifier when the adapter has an owner outside the runtime. Independent of the contribution mechanism and not a routing key. + [JsonPropertyName("ownerId")] + public string? OwnerId { get; set; } + + /// Descriptive provider family that produced this row; not a routing key. + [JsonPropertyName("providerKind")] + public string ProviderKind { get; set; } = string.Empty; + + /// Kind of component that supplied the adapter. + [JsonPropertyName("source")] + public ModelProviderProvenanceSource Source { get; set; } } -/// The model identifier active on the session after the switch. +/// Serializable reference to a discovered provider instance. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSwitchToResult +public sealed class ModelProviderInstanceReference { - /// Compaction confirmation projection when status is confirmation_required. - [JsonPropertyName("confirmation")] - public ModelSwitchConfirmation? Confirmation { get; set; } + /// Stable opaque identity of the adapter that owns this reference. Must be present in the target session's effective catalog. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; - /// True when the switch was deferred (enqueued as a cancellable `/model` command) because a turn was active or another model change was already queued, rather than applied immediately. When true, the session's live model is unchanged until the queued change drains. - [JsonPropertyName("deferred")] - public bool? Deferred { get; set; } + /// Stable instance identifier derived by the provider adapter, such as `ollama:{normalizedEndpoint}`. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Deprecation warnings associated with the selected model or options. - [JsonPropertyName("deprecationWarnings")] - public IList? DeprecationWarnings { get; set; } + /// Absolute provider management URI. The adapter validates normalization, supported schemes, and permission to access it against its bound configuration; a reference does not grant authority. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("managementEndpoint")] + public string ManagementEndpoint { get; set; } = string.Empty; - /// User-facing outcome message for the model switch. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Descriptive provider family. Must match the selected adapter; not a routing key. + [JsonPropertyName("providerKind")] + public string ProviderKind { get; set; } = string.Empty; +} - /// Currently active model identifier after the switch. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } +/// A normalized model-provider instance discovered by the runtime. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModelProviderInstance +{ + /// Human-readable instance name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Authoritative model and Auto preference state after an immediate switch. For deferred switches this remains the current state until the queued change drains. - [JsonPropertyName("modelState")] - public CurrentModel? ModelState { get; set; } + /// Inference API endpoint when the provider exposes one separately from its management endpoint. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("inferenceEndpoint")] + public string? InferenceEndpoint { get; set; } - /// Persistence failure encountered after applying the model switch. - [JsonPropertyName("persistenceError")] - public string? PersistenceError { get; set; } + /// Transport to use for inference against this instance. + [JsonPropertyName("inferenceTransport")] + public ProviderEndpointTransport? InferenceTransport { get; set; } - /// Stable queue item identifier when this request was enqueued. Remains present if the item drains before the response is returned. - [JsonPropertyName("queueId")] - public string? QueueId { get; set; } + /// Provider family to use for inference against this instance. + [JsonPropertyName("inferenceType")] + public ProviderEndpointType? InferenceType { get; set; } - /// Lifecycle result for the requested switch. - [JsonPropertyName("status")] - public string? Status { get; set; } + /// Wire API to use for inference against this instance, when required by the provider family. + [JsonPropertyName("inferenceWireApi")] + public ProviderEndpointWireApi? InferenceWireApi { get; set; } - /// User-facing warning produced while applying the model switch. - [JsonPropertyName("warning")] - public string? Warning { get; set; } -} + /// Attribution for the adapter that produced this instance. + [JsonPropertyName("provenance")] + public ModelProviderProvenance Provenance { get => field ??= new(); set; } -/// Environment variables consulted while resolving model-picker settings. -public sealed class ModelPickerSettingsContextEnvironment -{ + /// Self-contained reference for subsequent provider operations. + [JsonPropertyName("reference")] + public ModelProviderInstanceReference Reference { get => field ??= new(); set; } } -/// Filesystem and environment context used to resolve model-picker settings. +/// Typed provider-operation outcome. Use the code for control flow and the optional message for display. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelPickerSettingsContext +public sealed class ModelProviderOperationOutcome { - /// Optional Copilot configuration directory containing persisted settings. - [JsonPropertyName("configDir")] - public string? ConfigDir { get; set; } - - /// Environment variables consulted while resolving model-picker settings. - [JsonPropertyName("environment")] - public ModelPickerSettingsContextEnvironment Environment { get => field ??= new(); set; } + /// Machine-readable operation outcome. + [JsonPropertyName("code")] + public ModelProviderOperationOutcomeCode Code { get; set; } - /// User home directory used when resolving persisted settings. - [JsonPropertyName("homeDirectory")] - public string HomeDirectory { get; set; } = string.Empty; + /// Human-readable detail for non-success outcomes. + [JsonPropertyName("message")] + public string? Message { get; set; } } -/// RPC data type for ModelPickerPersistence operations. +/// Provider instances found by a discovery operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelPickerPersistenceRequest +public sealed class ModelProviderDiscoverResult { - /// Whether context tier was explicitly selected and should be persisted. - [JsonPropertyName("contextTierExplicit")] - public bool? ContextTierExplicit { get; set; } - - /// Whether reasoning effort was explicitly selected and should be persisted. - [JsonPropertyName("reasoningEffortExplicit")] - public bool? ReasoningEffortExplicit { get; set; } + /// Discovered provider instances. Empty when passive default discovery finds no reachable provider. + [JsonPropertyName("instances")] + public IList Instances { get => field ??= []; set; } - /// Filesystem and environment context used to resolve settings persistence. - [JsonPropertyName("settingsContext")] - public ModelPickerSettingsContext SettingsContext { get => field ??= new(); set; } + /// Typed operation outcome. Passive discovery can return `absent` with an empty instance list. + [JsonPropertyName("outcome")] + public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } } -/// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. +/// Provider discovery parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSwitchToRequest +internal sealed class ModelProviderDiscoverRequest { - /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. - [JsonPropertyName("compactionDecision")] - public string? CompactionDecision { get; set; } - - /// 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 ContextTier? ContextTier { get; set; } - - /// When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). - [JsonPropertyName("deferIfModelChangeQueued")] - public bool? DeferIfModelChangeQueued { get; set; } - - /// Override individual model capabilities resolved by the runtime. - [JsonPropertyName("modelCapabilities")] - public ModelCapabilitiesOverride? ModelCapabilities { get; set; } - - /// Settings scope used when persisting the selected model. - [JsonPropertyName("modelChangeScope")] - public string? ModelChangeScope { get; set; } - - /// Model selection id to switch to, as returned by `list`. A bare id (e.g. `claude-sonnet-4.6`) names a Copilot (CAPI) model; a provider-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a registry BYOK model. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; - - /// Optional settings context and explicit-override flags used to persist a picker selection. - [JsonPropertyName("pickerPersistence")] - public ModelPickerPersistenceRequest? PickerPersistence { get; set; } - - /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } - - /// Reasoning summary mode to request for supported model clients. - [JsonPropertyName("reasoningSummary")] - public ReasoningSummary? ReasoningSummary { get; set; } - - /// Optional repository settings scope to persist after the switch commits. - [JsonPropertyName("repoScope")] - public string? RepoScope { get; set; } - - /// Require the target to be currently available and enabled before applying the switch. - [JsonPropertyName("requireAvailable")] - public bool? RequireAvailable { get; set; } + /// Opaque adapter identity returned by `session.providers.getCatalog`. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; - /// When true, evaluate context-window compaction policy before applying the switch. - [JsonPropertyName("runCompactionPreflight")] - public bool? RunCompactionPreflight { get; set; } + /// Provider-specific JSON input. Omission or null selects adapter defaults unless requiresInput is true. Non-null input is validated against the advertised Draft 7 schema when present; otherwise validation belongs to the adapter. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. - [JsonPropertyName("source")] - public ModelChangeSource? Source { get; set; } - - /// Output verbosity level to request for supported models. - [JsonPropertyName("verbosity")] - public Verbosity? Verbosity { get; set; } } -/// Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed. +/// Current health information for a provider instance. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSwitchAutoTierResult +public sealed class ModelProviderStatus { - /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. - [JsonPropertyName("activatingAutoTier")] - public AutoTier? ActivatingAutoTier { get; set; } - - /// Auto preference currently committed for the session. - [JsonPropertyName("effectiveAutoTier")] - public AutoTier? EffectiveAutoTier { get; set; } + /// Normalized provider instance. + [JsonPropertyName("instance")] + public ModelProviderInstance Instance { get => field ??= new(); set; } - /// Latest unclaimed Auto preference waiting for a future user turn. - [JsonPropertyName("pendingAutoTier")] - public AutoTier? PendingAutoTier { get; set; } + /// Typed operation outcome. + [JsonPropertyName("outcome")] + public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } - /// Immediate request status. `pending` means accepted but not committed. + /// Open provider status value, such as `healthy`, `unreachable`, or `notInstalled`. [JsonPropertyName("status")] - public ModelSwitchAutoTierStatus Status { get; set; } + public string Status { get; set; } = string.Empty; - /// Earlier unclaimed preference replaced by this request. This can be present with either status, including when selecting the effective preference cancels pending work. - [JsonPropertyName("supersededAutoTier")] - public AutoTier? SupersededAutoTier { get; set; } + /// Provider-reported version. + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`. +/// Provider status request parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSwitchAutoTierRequest +internal sealed class ModelProviderGetStatusRequest { - /// Auto preference to activate when a future user turn using the `auto` model safely mints a replacement model and token pair. Pass null to return to provider-default Auto routing. - [JsonPropertyName("autoTier")] - [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - public AutoTier? AutoTier { get; set; } + /// Provider instance reference returned by discovery. + [JsonPropertyName("instance")] + public ModelProviderInstanceReference Instance { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Origin to record on the effective `session.model_change` event. Defaults to `sdk` when omitted. - [JsonPropertyName("source")] - public ModelChangeSource? Source { get; set; } } -/// Managed, repository, and CLI model overrides to overlay onto the session at startup. +/// Provider-reported model artifact metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelApplyStartupOverlayRequest +public sealed class ModelArtifactDetails { - /// Effective default Auto routing preference from user and managed settings. Applies only to fresh sessions and never replaces a per-session selection. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } + /// Provider-reported model architecture. + [JsonPropertyName("architecture")] + public string? Architecture { get; set; } - /// Model explicitly selected by the CLI, when provided. - [JsonPropertyName("cliModel")] - public string? CliModel { get; set; } + /// Provider-reported model families. + [JsonPropertyName("families")] + public IList? Families { get; set; } - /// Whether the overlay is being applied while resuming a deferred session. - [JsonPropertyName("deferredResume")] - public bool? DeferredResume { get; set; } + /// Primary model family. + [JsonPropertyName("family")] + public string? Family { get; set; } - /// Model required by device-managed policy, when configured. - [JsonPropertyName("deviceManagedModel")] - public string? DeviceManagedModel { get; set; } + /// Artifact format, such as `gguf`. + [JsonPropertyName("format")] + public string? Format { get; set; } - /// Context tier paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. - [JsonPropertyName("managedContextTier")] - public string? ManagedContextTier { get; set; } + /// Provider-reported parameter count label. + [JsonPropertyName("parameterSize")] + public string? ParameterSize { get; set; } - /// Reasoning effort paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. - [JsonPropertyName("managedReasoningEffort")] - public string? ManagedReasoningEffort { get; set; } + /// Provider-reported quantization label. + [JsonPropertyName("quantization")] + public string? Quantization { get; set; } - /// Startup default model from the enterprise policy helper, when configured. Weakest of the managed sources: it applies only when neither device nor server policy names a model, and an explicit user selection still wins. - [JsonPropertyName("policyHelperModel")] - public string? PolicyHelperModel { get; set; } + /// Provider-reported tokenizer. + [JsonPropertyName("tokenizer")] + public string? Tokenizer { get; set; } +} - /// Auto routing preference selected by repository settings, when configured. Applied only when the overlay selects the Auto model; beside a concrete model it stays dormant. - [JsonPropertyName("repoAutoTier")] - public string? RepoAutoTier { get; set; } +/// A non-fatal provider observation warning. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModelProviderWarning +{ + /// Machine-readable warning code. + [JsonPropertyName("code")] + public string Code { get; set; } = string.Empty; - /// Context tier selected by repository settings, when configured. - [JsonPropertyName("repoContextTier")] - public string? RepoContextTier { get; set; } + /// Human-readable warning message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; +} - /// Model selected by repository settings, when configured. - [JsonPropertyName("repoModel")] - public string? RepoModel { get; set; } +/// A model offered for agent conversations. Missing capability metadata does not disqualify a candidate. Models known to be incompatible, such as embedding-only models, are excluded by the adapter. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiscoveredModel +{ + /// Provider-reported model capabilities. Omitted capability fields are unknown; explicit false values are preserved. + [JsonPropertyName("capabilities")] + public ModelCapabilities Capabilities { get => field ??= new(); set; } - /// Reasoning effort selected by repository settings, when configured. - [JsonPropertyName("repoReasoningEffort")] - public string? RepoReasoningEffort { get; set; } + /// Provider-reported model artifact details. + [JsonPropertyName("details")] + public ModelArtifactDetails Details { get => field ??= new(); set; } - /// Model required by server-managed policy, when configured. - [JsonPropertyName("serverManagedModel")] - public string? ServerManagedModel { get; set; } + /// Provider-reported artifact digest. + [JsonPropertyName("digest")] + public string? Digest { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Provider-native model identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// The applied host allowlist and effective session model policy after intersection. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSetAllowedModelsResult -{ - /// Normalized host allowlist. Omitted when the host restriction was cleared, or when a relay client does not return the host policy. - [JsonPropertyName("allowedModels")] - public IList? AllowedModels { get; set; } + /// Provider-reported last-modified timestamp. + [JsonPropertyName("modifiedAt")] + public DateTimeOffset? ModifiedAt { get; set; } - /// Effective exact IDs or repository policy patterns after applying the host restriction. Omitted by relay clients that do not return the host policy. - [JsonPropertyName("effectiveAllowedModels")] - public IList? EffectiveAllowedModels { get; set; } + /// Provider-reported display name. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Effective deterministic fallback model, when the policy defines one. - [JsonPropertyName("fallbackModel")] - public string? FallbackModel { get; set; } + /// Attribution for the adapter that produced this model row. + [JsonPropertyName("provenance")] + public ModelProviderProvenance Provenance { get => field ??= new(); set; } - /// Selected session model after reconciling a now-disallowed concrete selection. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Provider-reported artifact size in bytes. + [JsonPropertyName("sizeBytes")] + public long? SizeBytes { get; set; } + + /// Non-fatal warnings encountered while enriching this model. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error. +/// Models offered for agent conversations by one provider instance. Adapters exclude known-incompatible models, but retain candidates with unknown capabilities. Listing does not guarantee compatibility. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSetAllowedModelsRequest +public sealed class DiscoveredModelList { - /// Exact model IDs to permit, or null to clear the host restriction. - [JsonPropertyName("allowedModels")] - public IList? AllowedModels { get; set; } + /// Provider-native models in provider order. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Typed operation outcome. + [JsonPropertyName("outcome")] + public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } } -/// 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. +/// Provider model inventory request parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSetReasoningEffortResult -{ - /// Reasoning effort level recorded on the session after the update. - [JsonPropertyName("reasoningEffort")] - public string ReasoningEffort { get; set; } = string.Empty; -} - -/// Reasoning effort level to apply to the currently selected model. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSetReasoningEffortRequest +internal sealed class ModelProviderModelsListRequest { - /// Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. - [JsonPropertyName("reasoningEffort")] - public string ReasoningEffort { get; set; } = string.Empty; + /// Provider instance reference returned by discovery. + [JsonPropertyName("instance")] + public ModelProviderInstanceReference Instance { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Cost-category metadata for a CAPI model. +/// Vision-specific limits. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionModelPriceCategory +public sealed class ModelCapabilitiesOverrideLimitsVision { - /// CAPI model identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Maximum image size in bytes. + [JsonPropertyName("max_prompt_image_size")] + public long? MaxPromptImageSize { get; set; } - /// Cost category assigned to the model. - [JsonPropertyName("priceCategory")] - public ModelPickerPriceCategory PriceCategory { get; set; } + /// Maximum number of images per prompt. + [JsonPropertyName("max_prompt_images")] + public long? MaxPromptImages { get; set; } + + /// MIME types the model accepts. + [JsonPropertyName("supported_media_types")] + public IList? SupportedMediaTypes { get; set; } } -/// One model provider available to the session — the model analog of the account `ProviderDescriptor`. Opaque id/label/kind plus a stable ordering; central code never branches on kind. +/// Token limits for prompts, outputs, and context window. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderDescriptor +public sealed class ModelCapabilitiesOverrideLimits { - /// Opaque, stable provider id, stamped onto every model this provider returns. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Maximum total context window size in tokens. + [JsonPropertyName("max_context_window_tokens")] + public long? MaxContextWindowTokens { get; set; } - /// The neutral provider kind. - [JsonPropertyName("kind")] - public ModelProviderKind Kind { get; set; } + /// Maximum number of output/completion tokens. + [JsonPropertyName("max_output_tokens")] + public long? MaxOutputTokens { get; set; } - /// Human-readable menu label, owned by the runtime so every consumer renders identical text. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// Maximum number of prompt/input tokens. + [JsonPropertyName("max_prompt_tokens")] + public long? MaxPromptTokens { get; set; } - /// Stable ordering key for presenting providers in a deterministic sequence. - [JsonPropertyName("ordering")] - public long Ordering { get; set; } + /// Vision-specific limits. + [JsonPropertyName("vision")] + public ModelCapabilitiesOverrideLimitsVision? Vision { get; set; } } -/// The list of models available to this session. +/// Feature flags indicating what the model supports. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionModelList +public sealed class ModelCapabilitiesOverrideSupports { - /// Available models, ordered with the most preferred default first. Includes both Copilot (CAPI) models and any registry BYOK models; a BYOK model appears under its provider-qualified selection id (`provider/id`). - [JsonPropertyName("list")] - public IList List { get => field ??= []; set; } - - /// Cost categories for the full CAPI catalog, including picker-disabled models that Auto may select. Metadata only; entries absent from `list` are not manually selectable. - [JsonPropertyName("modelPriceCategories")] - public IList? ModelPriceCategories { get; set; } + /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). + [JsonPropertyName("adaptive_thinking")] + public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } - /// The model providers available to this session, in ordering order, resolved from the account roster; empty when no provider is entitled (logged out / seatless). Each model in `list` carries its own provider reference; this roster gives the deterministic provider sequence and lets a consumer group by provider without deriving ordering from the model list. Central code never branches on a provider kind. - [JsonPropertyName("providers")] - public IList? Providers { get; set; } + /// Whether this model supports reasoning effort configuration. + [JsonPropertyName("reasoningEffort")] + public bool? ReasoningEffort { get; set; } - /// Per-quota snapshots returned alongside the model list, keyed by quota type. - [JsonPropertyName("quotaSnapshots")] - public IDictionary? QuotaSnapshots { get; set; } -} + /// Whether this model supports canonical tool calling. + [JsonPropertyName("toolCalls")] + public bool? ToolCalls { get; set; } -/// RPC data type for SessionModelList operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionModelListRequest -{ - /// If true, bypasses the per-session model list cache and re-fetches from CAPI. - [JsonPropertyName("skipCache")] - public bool? SkipCache { get; set; } + /// Whether this model supports vision/image input. + [JsonPropertyName("vision")] + public bool? Vision { get; set; } } -/// RPC data type for SessionModelListRequestWithSession operations. +/// Optional capability overrides (vision, tool_calls, reasoning, etc.). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModelListRequestWithSession +public sealed class ModelCapabilitiesOverride { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Token limits for prompts, outputs, and context window. + [JsonPropertyName("limits")] + public ModelCapabilitiesOverrideLimits? Limits { get; set; } - /// If true, bypasses the per-session model list cache and re-fetches from CAPI. - [JsonPropertyName("skipCache")] - public bool? SkipCache { get; set; } + /// Feature flags indicating what the model supports. + [JsonPropertyName("supports")] + public ModelCapabilitiesOverrideSupports? Supports { get; set; } } -/// Identifies the target session. +/// RPC data type for ProtocolSystemMessageAppendConfig operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModeGetRequest +public sealed class ProtocolSystemMessageAppendConfig { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Text appended to the standard system prompt. + [JsonPropertyName("content")] + public string? Content { get; set; } + + /// Append-mode discriminator. Omission also selects append mode. + [JsonPropertyName("mode")] + public ProtocolAppendMode? Mode { get; set; } } -/// Outcome of a session mode change, including any model switch it triggered and follow-up the host must perform. +/// RPC data type for SystemMessageBlock operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModeSetResult +public sealed class SystemMessageBlock { - /// Whether the host should arm an interactive continuation after the mode change. - [JsonPropertyName("armInteractiveContinuation")] - public bool? ArmInteractiveContinuation { get; set; } - - /// Compaction confirmation required before the mode change can complete. - [JsonPropertyName("confirmation")] - public ModelSwitchConfirmation? Confirmation { get; set; } - - /// Whether the host must defer implementing the requested mode change. - [JsonPropertyName("deferImplementation")] - public bool? DeferImplementation { get; set; } - - /// Deprecation warnings associated with the model selected by the mode change. - [JsonPropertyName("deprecationWarnings")] - public IList? DeprecationWarnings { get; set; } - - /// User-facing outcome message for the model switch triggered by the mode change. - [JsonPropertyName("message")] - public string? Message { get; set; } - - /// Whether the requested mode was applied to the session. False only when an 'expectedMode' precondition did not hold, in which case any model change reported alongside it was still applied. - [JsonPropertyName("modeApplied")] - public bool? ModeApplied { get; set; } - - /// Whether applying the mode changed the active model. - [JsonPropertyName("modelChanged")] - public bool ModelChanged { get; set; } + /// Whether providers with explicit prompt caching should place a cache breakpoint after this block. + [JsonPropertyName("cacheBreakpoint")] + public bool? CacheBreakpoint { get; set; } - /// Lifecycle status of the requested mode change. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; + /// Text content for this system-message block. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// User-facing warning produced while applying the mode change. - [JsonPropertyName("warning")] - public string? Warning { get; set; } + /// Whether the block is static and may be cached independently of dynamic prompt content. + [JsonPropertyName("isStatic")] + public bool? IsStatic { get; set; } } -/// Agent interaction mode to apply to the session. +/// RPC data type for ProtocolSystemMessageReplaceConfig operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModeSetRequest +public sealed class ProtocolSystemMessageReplaceConfig { - /// Explicit response to a model-switch compaction preflight. - [JsonPropertyName("compactionDecision")] - public string? CompactionDecision { get; set; } - - /// Mode the session must currently be in for the change to apply. When set and the session is in a different mode the request is a no-op and reports status 'unchanged'. - [JsonPropertyName("expectedMode")] - public SessionMode? ExpectedMode { get; set; } + /// Complete replacement system-message text. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Session whose plan-mode base state should be inherited. - [JsonPropertyName("inheritPlanBaseFromSessionId")] - public string? InheritPlanBaseFromSessionId { get; set; } + /// Optional structured blocks corresponding to the replacement content. + [JsonPropertyName("contentBlocks")] + public IList? ContentBlocks { get; set; } - /// The session mode the agent is operating in. + /// Replace-mode discriminator. [JsonPropertyName("mode")] - public SessionMode Mode { get; set; } - - /// Whether the selected plan model should be persisted. - [JsonPropertyName("persistPlanSelection")] - public bool? PersistPlanSelection { get; set; } - - /// Settings context used when persisting the selected plan model. - [JsonPropertyName("pickerSettingsContext")] - public ModelPickerSettingsContext? PickerSettingsContext { get; set; } - - /// Context tier to use with the dedicated plan model. - [JsonPropertyName("planContextTier")] - public string? PlanContextTier { get; set; } - - /// Action to perform when leaving plan mode. - [JsonPropertyName("planExitAction")] - public string? PlanExitAction { get; set; } - - /// Dedicated model to use in plan mode, when configured. - [JsonPropertyName("planModel")] - public string? PlanModel { get; set; } - - /// Whether a dedicated plan model is configured. - [JsonPropertyName("planModelConfigured")] - public bool? PlanModelConfigured { get; set; } - - /// Reasoning effort to use with the dedicated plan model. - [JsonPropertyName("planReasoningEffort")] - public string? PlanReasoningEffort { get; set; } - - /// Whether leaving plan mode should restore the session's previous model. - [JsonPropertyName("restorePlanModel")] - public bool? RestorePlanModel { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public ProtocolReplaceMode Mode { get; set; } } -/// The session's friendly name, or null when not yet set. +/// RPC data type for ProtocolStaticSectionOverride operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class NameGetResult +public sealed class ProtocolStaticSectionOverride { - /// The session name (user-set or auto-generated), or null if not yet set. - [JsonPropertyName("name")] - public string? Name { get; set; } -} + /// Declarative operation applied to the section. + [JsonPropertyName("action")] + public ProtocolStaticSectionAction Action { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionNameGetRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional content used by replace, append, and prepend operations. + [JsonPropertyName("content")] + public string? Content { get; set; } } -/// New friendly name to apply to the session. +/// Polymorphic base type discriminated by action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class NameSetRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "action", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(ProtocolMarkerSectionOverrideTransform), "transform")] +[JsonDerivedType(typeof(ProtocolMarkerSectionOverridePreserve), "preserve")] +public partial class ProtocolMarkerSectionOverride { - /// New session name (1–100 characters, trimmed of leading/trailing whitespace). - [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)] - [MaxLength(100)] - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("action")] + public virtual string Action { get; set; } = string.Empty; } -/// Indicates whether the auto-generated summary was applied as the session's name. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class NameSetAutoResult -{ - /// Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. - [JsonPropertyName("applied")] - public bool Applied { get; set; } -} -/// Auto-generated session summary to apply as the session's name when no user-set name exists. +/// The transform variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class NameSetAutoRequest +public partial class ProtocolMarkerSectionOverrideTransform : ProtocolMarkerSectionOverride { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - - /// Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. - [JsonPropertyName("summary")] - public string Summary { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Action => "transform"; } -/// Existence, contents, and resolved path of the session plan file. +/// The preserve variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanReadResult +public partial class ProtocolMarkerSectionOverridePreserve : ProtocolMarkerSectionOverride { - /// The content of the plan file, or null if it does not exist. - [JsonPropertyName("content")] - public string? Content { get; set; } - - /// Whether the plan file exists in the workspace. - [JsonPropertyName("exists")] - public bool Exists { get; set; } - - /// Absolute file path of the plan file, or null if workspace is not enabled. - [JsonPropertyName("path")] - public string? Path { get; set; } + /// + [JsonIgnore] + public override string Action => "preserve"; } -/// Identifies the target session. +/// JSON union data type for ProtocolSectionOverride. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanReadRequest +[JsonConverter(typeof(Converter))] +public sealed partial class ProtocolSectionOverride { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Gets the value when this instance contains . + public ProtocolStaticSectionOverride? ProtocolStaticSectionOverride { get; } -/// Replacement contents to write to the session plan file. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PlanUpdateRequest -{ - /// The new content for the plan file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Gets the value when this instance contains . + public ProtocolMarkerSectionOverride? ProtocolMarkerSectionOverride { get; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Initializes a new instance of the class from . + public ProtocolSectionOverride(ProtocolStaticSectionOverride value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolStaticSectionOverride = value; + } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanDeleteRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Converts to . + public static implicit operator ProtocolSectionOverride(ProtocolStaticSectionOverride value) => new(value); -/// A single todo row read from the session SQL `todos` table. All fields are optional because the SQL schema is best-effort and the agent may not have populated every column. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanSqlTodosRow -{ - /// Todo creation time, as stored by the session SQL schema's `datetime('now')` default: `YYYY-MM-DD HH:MM:SS` in UTC. Lets clients attribute todos to the work item that created them (e.g. scoping a goal's progress to the todos it produced) rather than to the whole session. - [JsonPropertyName("createdAt")] - public string? CreatedAt { get; set; } + /// Initializes a new instance of the class from . + public ProtocolSectionOverride(ProtocolMarkerSectionOverride value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolMarkerSectionOverride = value; + } - /// Todo description. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Converts to . + public static implicit operator ProtocolSectionOverride(ProtocolMarkerSectionOverride value) => new(value); - /// Todo identifier. - [JsonPropertyName("id")] - public string? Id { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ProtocolSectionOverride Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + throw new JsonException("Expected JSON object for ProtocolSectionOverride."); + } - /// Todo status. - [JsonPropertyName("status")] - public string? Status { get; set; } + using var document = JsonDocument.ParseValue(ref reader); + var element = document.RootElement; + if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "replace" || element.GetProperty("action").GetString() == "remove" || element.GetProperty("action").GetString() == "append" || element.GetProperty("action").GetString() == "prepend"))) + { + var protocolStaticSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolStaticSectionOverride); + return protocolStaticSectionOverride is null ? throw new JsonException("Expected ProtocolStaticSectionOverride value.") : new ProtocolSectionOverride(protocolStaticSectionOverride); + } + if ((element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "transform")) || element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "preserve")))) + { + var protocolMarkerSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolMarkerSectionOverride); + return protocolMarkerSectionOverride is null ? throw new JsonException("Expected ProtocolMarkerSectionOverride value.") : new ProtocolSectionOverride(protocolMarkerSectionOverride); + } - /// Todo title. - [JsonPropertyName("title")] - public string? Title { get; set; } -} + throw new JsonException("JSON value did not match any ProtocolSectionOverride variant."); + } -/// Todo rows read from the session SQL database. Empty when no session database is available. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanReadSqlTodosResult -{ - /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. - [JsonPropertyName("rows")] - public IList Rows { get => field ??= []; set; } -} + /// + public override void Write(Utf8JsonWriter writer, ProtocolSectionOverride value, JsonSerializerOptions options) + { + if (value.ProtocolStaticSectionOverride is { } protocolStaticSectionOverride) + { + JsonSerializer.Serialize(writer, protocolStaticSectionOverride, RpcJsonContext.Default.ProtocolStaticSectionOverride); + return; + } + if (value.ProtocolMarkerSectionOverride is { } protocolMarkerSectionOverride) + { + JsonSerializer.Serialize(writer, protocolMarkerSectionOverride, RpcJsonContext.Default.ProtocolMarkerSectionOverride); + return; + } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanReadSqlTodosRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + throw new JsonException("No ProtocolSectionOverride variant value is set."); + } + } } -/// A single dependency edge read from the session SQL `todo_deps` table, indicating that one todo must complete before another. +/// RPC data type for ProtocolSystemMessageCustomizeConfig operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanSqlTodoDependency +public sealed class ProtocolSystemMessageCustomizeConfig { - /// ID of the todo it depends on. - [JsonPropertyName("dependsOn")] - public string DependsOn { get; set; } = string.Empty; - - /// ID of the todo that has the dependency. - [JsonPropertyName("todoId")] - public string TodoId { get; set; } = string.Empty; -} + /// Text appended after the customized sections. + [JsonPropertyName("content")] + public string? Content { get; set; } -/// Todo rows + dependency edges read from the session SQL database. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanReadSqlTodosWithDependenciesResult -{ - /// Edges from the session SQL todo_deps table. Empty when no database, no todo_deps table, or the SELECT failed. Read independently from `rows`, so a broken todo_deps table does not affect the rows result and vice versa. - [JsonPropertyName("dependencies")] - public IList Dependencies { get => field ??= []; set; } + /// Customize-mode discriminator. + [JsonPropertyName("mode")] + public ProtocolCustomizeMode Mode { get; set; } - /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. Empty when no database, no todos table, or the SELECT failed. - [JsonPropertyName("rows")] - public IList Rows { get => field ??= []; set; } + /// Named standard-prompt section overrides. + [JsonPropertyName("sections")] + public IDictionary? Sections { get; set; } } -/// Identifies the target session. +/// JSON union data type for ProtocolSystemMessageConfig. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanReadSqlTodosWithDependenciesRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} - -/// RPC data type for WorkspacesGetWorkspaceResultWorkspace operations. -public sealed class WorkspacesGetWorkspaceResultWorkspace +[JsonConverter(typeof(Converter))] +public sealed partial class ProtocolSystemMessageConfig { - /// Current Git branch. - [JsonPropertyName("branch")] - public string? Branch { get; set; } + /// Gets the value when this instance contains . + public ProtocolSystemMessageAppendConfig? ProtocolSystemMessageAppendConfig { get; } - /// Whether the per-session Chronicle upgrade prompt was dismissed for the workspace. - [JsonPropertyName("chronicle_sync_dismissed")] - public bool? ChronicleSyncDismissed { get; set; } + /// Gets the value when this instance contains . + public ProtocolSystemMessageReplaceConfig? ProtocolSystemMessageReplaceConfig { get; } - /// Name of the client that created the workspace. - [JsonPropertyName("client_name")] - public string? ClientName { get; set; } + /// Gets the value when this instance contains . + public ProtocolSystemMessageCustomizeConfig? ProtocolSystemMessageCustomizeConfig { get; } - /// Timestamp when the workspace was created. - [JsonPropertyName("created_at")] - public DateTimeOffset? CreatedAt { get; set; } + /// Initializes a new instance of the class from . + public ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolSystemMessageAppendConfig = value; + } - /// Current working directory associated with the workspace. - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Converts to . + public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) => new(value); - /// Git repository root associated with the workspace. - [JsonPropertyName("git_root")] - public string? GitRoot { get; set; } + /// Initializes a new instance of the class from . + public ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolSystemMessageReplaceConfig = value; + } - /// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration. - [JsonPropertyName("host_type")] - public WorkspacesWorkspaceDetailsHostType? HostType { get; set; } + /// Converts to . + public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) => new(value); - /// Stable workspace identifier. - [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)] + /// Initializes a new instance of the class from . + public ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolSystemMessageCustomizeConfig = value; + } + + /// Converts to . + public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) => new(value); + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ProtocolSystemMessageConfig Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + throw new JsonException("Expected JSON object for ProtocolSystemMessageConfig."); + } + + using var document = JsonDocument.ParseValue(ref reader); + var element = document.RootElement; + if (element.ValueKind == JsonValueKind.Object && (!element.TryGetProperty("mode", out _) || (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "append")))) + { + var protocolSystemMessageAppendConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); + return protocolSystemMessageAppendConfig is null ? throw new JsonException("Expected ProtocolSystemMessageAppendConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageAppendConfig); + } + if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "replace"))) + { + var protocolSystemMessageReplaceConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); + return protocolSystemMessageReplaceConfig is null ? throw new JsonException("Expected ProtocolSystemMessageReplaceConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageReplaceConfig); + } + if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "customize"))) + { + var protocolSystemMessageCustomizeConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); + return protocolSystemMessageCustomizeConfig is null ? throw new JsonException("Expected ProtocolSystemMessageCustomizeConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageCustomizeConfig); + } + + throw new JsonException("JSON value did not match any ProtocolSystemMessageConfig variant."); + } + + /// + public override void Write(Utf8JsonWriter writer, ProtocolSystemMessageConfig value, JsonSerializerOptions options) + { + if (value.ProtocolSystemMessageAppendConfig is { } protocolSystemMessageAppendConfig) + { + JsonSerializer.Serialize(writer, protocolSystemMessageAppendConfig, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); + return; + } + if (value.ProtocolSystemMessageReplaceConfig is { } protocolSystemMessageReplaceConfig) + { + JsonSerializer.Serialize(writer, protocolSystemMessageReplaceConfig, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); + return; + } + if (value.ProtocolSystemMessageCustomizeConfig is { } protocolSystemMessageCustomizeConfig) + { + JsonSerializer.Serialize(writer, protocolSystemMessageCustomizeConfig, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); + return; + } + + throw new JsonException("No ProtocolSystemMessageConfig variant value is set."); + } + } +} + +/// A BYOK model definition referencing a named provider. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderModelConfig +{ + /// Optional capability overrides (vision, tool_calls, reasoning, etc.). + [JsonPropertyName("capabilities")] + public ModelCapabilitiesOverride? Capabilities { get; set; } + + /// Provider-local model id, unique within its provider. The session-wide selection id (shown in the model list and passed to switchTo) is the provider-qualified `provider/id`. [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; - /// Most recent Mission Control event identifier observed for the workspace. - [JsonPropertyName("mc_last_event_id")] - public string? McLastEventId { get; set; } + /// Maximum context window tokens for the model. + [JsonPropertyName("maxContextWindowTokens")] + public double? MaxContextWindowTokens { get; set; } - /// Mission Control session identifier associated with the workspace. - [JsonPropertyName("mc_session_id")] - public string? McSessionId { get; set; } + /// Maximum output tokens for the model. + [JsonPropertyName("maxOutputTokens")] + public double? MaxOutputTokens { get; set; } - /// Mission Control task identifier associated with the workspace. - [JsonPropertyName("mc_task_id")] - public string? McTaskId { get; set; } + /// Maximum prompt/input tokens for the model. + [JsonPropertyName("maxPromptTokens")] + public double? MaxPromptTokens { get; set; } - /// Workspace display name. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Provider-published model metadata, preserved verbatim as the public Model.metadata object. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } - /// Whether the workspace session can be steered remotely. - [JsonPropertyName("remote_steerable")] - public bool? RemoteSteerable { get; set; } + /// Well-known base model id used for behavior/capability/config lookup. Defaults to `id`. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } - /// Repository identifier associated with the workspace. - [JsonPropertyName("repository")] - public string? Repository { get; set; } + /// Display name for model pickers. Defaults to the provider-qualified selection id (`provider/id`). + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Number of persisted summaries in the workspace. - [JsonPropertyName("summary_count")] - public long? SummaryCount { get; set; } + /// Name of the configured provider that serves this model. + [JsonPropertyName("provider")] + public string Provider { get; set; } = string.Empty; - /// Timestamp when the workspace was last updated. - [JsonPropertyName("updated_at")] - public DateTimeOffset? UpdatedAt { get; set; } + /// System-message configuration used when the runtime builds the standard prompt for this provider-qualified model, including general-purpose subagents. It uses the same object hierarchy as session-level systemMessage configuration, except transform actions are rejected because the current callback protocol is not model-scoped. When present, it overrides the session-wide configuration on those prompt paths. Selected custom-agent and specialized-subagent prompts remain authoritative. + [JsonPropertyName("systemMessage")] + public ProtocolSystemMessageConfig? SystemMessage { get; set; } - /// Whether the workspace name was explicitly chosen by the user. - [JsonPropertyName("user_named")] - public bool? UserNamed { get; set; } + /// The model name sent to the provider API for inference. Defaults to `id`. + [JsonPropertyName("wireModel")] + public string? WireModel { get; set; } } -/// Current workspace metadata for the session, including its absolute filesystem path when available. +/// Azure-specific provider options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesGetWorkspaceResult +public sealed class ProviderConfigAzure { - /// Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). - [JsonPropertyName("path")] - public string? Path { get; set; } - - /// Current workspace metadata, or null if not available. - [JsonPropertyName("workspace")] - public WorkspacesGetWorkspaceResultWorkspace? Workspace { get; set; } + /// API version. When set, uses the versioned deployment route. When omitted, uses the GA versionless v1 route. + [JsonPropertyName("apiVersion")] + public string? ApiVersion { get; set; } } -/// Identifies the target session. +/// External SDK input for a named custom model provider. Ingested by the native protocol boundary before host dispatch. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesGetWorkspaceRequest +public sealed class NamedProviderConfig { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Static API key used to authenticate provider requests. + [JsonPropertyName("apiKey")] + public string? ApiKey { get; set; } + + /// Azure authentication configuration for the provider. + [JsonPropertyName("azure")] + public ProviderConfigAzure? Azure { get; set; } + + /// Base URL for provider API requests. + [JsonPropertyName("baseUrl")] + public string BaseUrl { get; set; } = string.Empty; + + /// Static bearer token used to authenticate provider requests. + [JsonPropertyName("bearerToken")] + public string? BearerToken { get; set; } + + /// Whether the host supplies bearer tokens dynamically. + [JsonPropertyName("hasBearerTokenProvider")] + public bool? HasBearerTokenProvider { get; set; } + + /// Additional HTTP headers included with provider requests. + [JsonPropertyName("headers")] + public IDictionary? Headers { get; set; } + + /// The product serving the provider's models, reported in telemetry as `model_provider`. Only affects telemetry. + [JsonPropertyName("modelProvider")] + public ProviderConfigModelProvider? ModelProvider { get; set; } + + /// Unique provider name used to qualify model selection IDs. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Transport used to communicate with the provider. + [JsonPropertyName("transport")] + public ProviderConfigTransport? Transport { get; set; } + + /// Provider protocol family. + [JsonPropertyName("type")] + public ProviderConfigType? Type { get; set; } + + /// Wire API used to communicate with the provider. + [JsonPropertyName("wireApi")] + public ProviderConfigWireApi? WireApi { get; set; } } -/// Workspace metadata fields to update. +/// Provider configuration prepared from a discovered model. Preparing a plan changes nothing: it neither registers the model with the session nor writes durable configuration. To apply it, pass `provider` and `model` to `session.provider.add`, omitting whichever the dispositions report as already configured. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesUpdateMetadataRequest +public sealed class ModelProviderConfigurationPlan { - /// Opaque workspace context supplied by the session host. - [JsonPropertyName("context")] - public JsonElement? Context { get; set; } + /// Model definition prepared from the discovered model. Capability fields the provider did not report stay omitted rather than being asserted false. + [JsonPropertyName("model")] + public ProviderModelConfig Model { get => field ??= new(); set; } - /// Optional workspace display name override. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Whether `model` still needs to be registered. When `alreadyConfigured`, `selectionId` is already registered and the caller can select it without adding anything. + [JsonPropertyName("modelDisposition")] + public ModelProviderConfigurationDisposition ModelDisposition { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Provider connection prepared from the instance's inference metadata. Carries no credential; supply one if the endpoint requires it. + [JsonPropertyName("provider")] + public NamedProviderConfig Provider { get => field ??= new(); set; } + + /// Whether `provider` still needs to be registered. When `alreadyConfigured`, a provider with the same endpoint is already registered and `provider` restates it under its existing name; adding it again is rejected as a duplicate. + [JsonPropertyName("providerDisposition")] + public ModelProviderConfigurationDisposition ProviderDisposition { get; set; } + + /// Provider-qualified selection id (`provider/id`) to pass to `switchTo` once the plan is applied. + [JsonPropertyName("selectionId")] + public string SelectionId { get; set; } = string.Empty; + + /// Non-fatal warnings carried over from the discovered model, such as capabilities the provider did not report. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// Optional session context used when creating a local workspace. +/// A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesEnsureRequest +internal sealed class ModelProviderPrepareConfigurationRequest { - /// Opaque workspace context supplied by the session host. - [JsonPropertyName("context")] - public JsonElement? Context { get; set; } + /// The discovered instance that serves the model. + [JsonPropertyName("instance")] + public ModelProviderInstance Instance { get => field ??= new(); set; } + + /// The discovered model to configure. + [JsonPropertyName("model")] + public DiscoveredModel Model { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Relative paths of files stored in the session workspace files directory. +/// Managed sandbox enforcement state for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesListFilesResult +public sealed class SandboxEnforcementStatus { - /// Slash-separated relative file paths in the workspace files directory. - [JsonPropertyName("files")] - public IList Files { get => field ??= []; set; } + /// Whether an enforcement failure has permanently blocked the session. + [JsonPropertyName("blocked")] + public bool Blocked { get; set; } + + /// The first sandbox enforcement failure that blocked the session. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether the effective managed policy requires an available sandbox backend. + [JsonPropertyName("required")] + public bool Required { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesListFilesRequest +internal sealed class SessionSandboxGetEnforcementStatusRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Contents of the requested workspace file as a UTF-8 string. +/// A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesReadFileResult +public sealed class SandboxCredentialSuggestion { - /// File content as a UTF-8 string. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Environment variable name. The secret value is never returned. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. + [JsonPropertyName("suggestedInjectHosts")] + public IList SuggestedInjectHosts { get => field ??= []; set; } } -/// Relative path of the workspace file to read. +/// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesReadFileRequest +public sealed class SandboxCredentialSuggestionsResult { - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. + [JsonPropertyName("suggestions")] + public IList Suggestions { get => field ??= []; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSandboxGetCredentialSuggestionsRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Relative path and UTF-8 content for the workspace file to create or overwrite. +/// Result of attempting to disable sandboxing for the current session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesCreateFileRequest +public sealed class SandboxDisableForSessionResult { - /// File content to write as a UTF-8 string. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; - - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// The authoritative sandbox enabled state after the operation. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether this call resolved the pending request and applied the session opt-out. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Filesystem metadata for a path in the session workspace files directory. +/// Optional informational context describing how and where the permission decision was made. This does not affect permission behavior. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesStatFileResult +public sealed class PermissionDecisionContext { - /// Creation time in Unix epoch milliseconds. - [JsonPropertyName("birthtimeMs")] - public double BirthtimeMs { get; set; } - - /// Whether the path identifies a directory. - [JsonPropertyName("isDirectory")] - public bool IsDirectory { get; set; } + /// Disposition of the permission request as observed by the responding client. + [JsonPropertyName("outcome")] + public PermissionDecisionOutcome Outcome { get; set; } - /// Whether the path identifies a regular file. - [JsonPropertyName("isFile")] - public bool IsFile { get; set; } + /// Whether the responding client could ask a user interactively, was running headlessly, or had no response path. Omit when the client cannot determine this authoritatively. + [JsonPropertyName("responseCapability")] + public PermissionResponseCapability? ResponseCapability { get; set; } - /// Last modification time in Unix epoch milliseconds. - [JsonPropertyName("mtimeMs")] - public double MtimeMs { get; set; } + /// Controlled reason or actor responsible for the response. + [JsonPropertyName("source")] + public PermissionDecisionSource Source { get; set; } - /// Size in bytes. - [JsonPropertyName("size")] - public double Size { get; set; } + /// Client surface that submitted the response. + [JsonPropertyName("surface")] + public PermissionDecisionSurface Surface { get; set; } } -/// Relative path of the workspace file or directory to inspect. +/// Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesStatFileRequest +internal sealed class SandboxDisableForSessionRequest { - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Optional attribution for the permission decision. + [JsonPropertyName("decisionContext")] + public PermissionDecisionContext? DecisionContext { get; set; } + + /// Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Directory to create within the session workspace files directory. +/// Result of accepting a sandbox path grant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesCreateDirectoryRequest +public sealed class SandboxGrantPathForRequestResult { - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Whether to create missing parent directories. Defaults to false. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether this call resolved the pending request and added the path to the session's sandbox policy. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// File or directory to remove from the session workspace files directory. +/// Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesRemovePathRequest +internal sealed class SandboxGrantPathForRequestRequest { - /// Whether a missing path should be treated as success. Defaults to false. - [JsonPropertyName("force")] - public bool? Force { get; set; } - - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Optional attribution for the permission decision. + [JsonPropertyName("decisionContext")] + public PermissionDecisionContext? DecisionContext { get; set; } - /// Whether to remove directory contents recursively. Defaults to false. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } + /// Identifier of the exact pending sandbox escalation permission request whose sandboxPathGrant to accept. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Source and destination paths for a rename within the session workspace files directory. +/// Authentication status and account metadata for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesRenamePathRequest +public sealed class SessionAuthStatus { - /// Slash-separated destination path relative to the workspace files directory. - [JsonPropertyName("destination")] - public string Destination { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Authentication type. + [JsonPropertyName("authType")] + public AuthInfoType? AuthType { get; set; } - /// Slash-separated source path relative to the workspace files directory. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; -} + /// Copilot plan tier (e.g., individual_pro, business). + [JsonPropertyName("copilotPlan")] + public string? CopilotPlan { get; set; } -/// Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint filename. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesCheckpoints -{ - /// Filename of the checkpoint within the workspace checkpoints directory. - [JsonPropertyName("filename")] - public string Filename { get; set; } = string.Empty; + /// Authentication host URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public string? Host { get; set; } - /// Checkpoint number assigned by the workspace manager. - [JsonPropertyName("number")] - public long Number { get; set; } + /// Whether the session has resolved authentication. + [JsonPropertyName("isAuthenticated")] + public bool IsAuthenticated { get; set; } - /// Human-readable checkpoint title. - [JsonPropertyName("title")] - public string Title { get; set; } = string.Empty; -} + /// Authenticated login/username, if available. + [JsonPropertyName("login")] + public string? Login { get; set; } -/// Workspace checkpoints in chronological order; empty when the workspace is not enabled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesListCheckpointsResult -{ - /// Workspace checkpoints in chronological order. Empty when workspace is not enabled. - [JsonPropertyName("checkpoints")] - public IList Checkpoints { get => field ??= []; set; } + /// Human-readable authentication status description. + [JsonPropertyName("statusMessage")] + public string? StatusMessage { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesListCheckpointsRequest +internal sealed class SessionGitHubAuthGetStatusRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesReadCheckpointResult -{ - /// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. - [JsonPropertyName("content")] - public string? Content { get; set; } -} - -/// Checkpoint number to read. +/// Indicates whether the credential update succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesReadCheckpointRequest +public sealed class SessionSetCredentialsResult { - /// Checkpoint number to read. - [JsonPropertyName("number")] - public long Number { get; set; } + /// Whether the session ended up with a populated `copilotUser` for the installed credentials. `true` when the supplied credential already carried `copilotUser` or it was successfully re-resolved server-side. `false` when the credential is installed without `copilotUser` — either re-resolution failed, or the variant cannot be re-resolved from the credential alone (only the raw-token variants `token`, `env`, and `gh-cli` can). In both `false` cases the token swap still applied, but plan/quota/billing metadata is degraded. Present whenever a credential was supplied; omitted only when no credential was supplied (no-op call). + [JsonPropertyName("copilotUserResolved")] + public bool? CopilotUserResolved { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Metadata for the persisted summary. -public sealed class WorkspacesAddSummaryResultSummary +/// Authentication credentials accepted by session.gitHubAuth.setCredentials. Session-owned token-provider identities cannot be installed through this method. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SettableAuthInfoHmac), "hmac")] +[JsonDerivedType(typeof(SettableAuthInfoEnv), "env")] +[JsonDerivedType(typeof(SettableAuthInfoToken), "token")] +[JsonDerivedType(typeof(SettableAuthInfoCopilotApiToken), "copilot-api-token")] +[JsonDerivedType(typeof(SettableAuthInfoUser), "user")] +[JsonDerivedType(typeof(SettableAuthInfoAccount), "account")] +[JsonDerivedType(typeof(SettableAuthInfoGhCli), "gh-cli")] +[JsonDerivedType(typeof(SettableAuthInfoApiKey), "api-key")] +public partial class SettableAuthInfo { + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Refreshed metadata for the containing workspace. -public sealed class WorkspacesAddSummaryResultWorkspace -{ -} -/// Persisted summary metadata and refreshed workspace metadata. +/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. +/// The hmac variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesAddSummaryResult +public partial class SettableAuthInfoHmac : SettableAuthInfo { - /// Metadata for the persisted summary. - [JsonPropertyName("summary")] - public WorkspacesAddSummaryResultSummary? Summary { get; set; } + /// + [JsonIgnore] + public override string Type => "hmac"; - /// Refreshed metadata for the containing workspace. - [JsonPropertyName("workspace")] - public WorkspacesAddSummaryResultWorkspace? Workspace { get; set; } + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// HMAC secret used to sign requests. + [JsonPropertyName("hmac")] + public required string Hmac { get; set; } + + /// Authentication host. HMAC auth always targets the public GitHub host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// Compaction summary checkpoint to persist. +/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. +/// The env variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesAddSummaryRequest +public partial class SettableAuthInfoEnv : SettableAuthInfo { - /// Markdown summary content to persist. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "env"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Summary title shown in checkpoint listings. - [JsonPropertyName("title")] - public string Title { get; set; } = string.Empty; -} + /// Name of the environment variable the token was sourced from. + [JsonPropertyName("envVar")] + public required string EnvVar { get; set; } -/// Rollback point for local workspace summaries. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesTruncateSummariesRequest -{ - /// Number of newest summaries to keep. - [JsonPropertyName("keepCount")] - public long KeepCount { get; set; } + /// Authentication host (e.g. https://github.com or a GHES host). + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("login")] + public string? Login { get; set; } -/// Autopilot objective file content, or null when missing. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesReadAutopilotObjectiveResult -{ - /// Autopilot objective file content, or null when missing. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// Identifies the target session. +/// Token authentication accepted by session.gitHubAuth.setCredentials. +/// The token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesReadAutopilotObjectiveRequest +public partial class SettableAuthInfoToken : SettableAuthInfo { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Type => "token"; -/// Result of writing the autopilot objective file. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesWriteAutopilotObjectiveResult -{ - /// Filesystem operation performed. - [JsonPropertyName("operation")] - public string Operation { get; set; } = string.Empty; -} + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } -/// Autopilot objective file content to persist. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesWriteAutopilotObjectiveRequest -{ - /// Autopilot objective file content. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// Result of deleting the autopilot objective file. +/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. +/// The copilot-api-token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesDeleteAutopilotObjectiveResult +public partial class SettableAuthInfoCopilotApiToken : SettableAuthInfo { - /// True when a file was deleted. - [JsonPropertyName("deleted")] - public bool Deleted { get; set; } -} + /// + [JsonIgnore] + public override string Type => "copilot-api-token"; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesDeleteAutopilotObjectiveRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } -/// Whether the autopilot objective file exists. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesAutopilotObjectiveExistsResult -{ - /// True when the objective file exists. - [JsonPropertyName("exists")] - public bool Exists { get; set; } + /// Authentication host (always the public GitHub host). + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// Identifies the target session. +/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. +/// The user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesAutopilotObjectiveExistsRequest +public partial class SettableAuthInfoUser : SettableAuthInfo { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Type => "user"; -/// RPC data type for WorkspacesSaveLargePasteResultSaved operations. -public sealed class WorkspacesSaveLargePasteResultSaved -{ - /// Filename within the workspace files directory. - [JsonPropertyName("filename")] - public string Filename { get; set; } = string.Empty; + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Absolute filesystem path to the saved paste file. - [JsonPropertyName("filePath")] - public string FilePath { get; set; } = string.Empty; + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Size of the saved file in bytes. - [JsonPropertyName("sizeBytes")] - public long SizeBytes { get; set; } + /// OAuth user login. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// Descriptor for the saved paste file, or null when the workspace is unavailable. +/// An interactive account whose model provider owns its credentials. It carries no GitHub credential. +/// The account variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesSaveLargePasteResult +public partial class SettableAuthInfoAccount : SettableAuthInfo { - /// Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions). - [JsonPropertyName("saved")] - public WorkspacesSaveLargePasteResultSaved? Saved { get; set; } -} + /// + [JsonIgnore] + public override string Type => "account"; -/// Pasted content to save as a UTF-8 file in the session workspace. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesSaveLargePasteRequest -{ - /// Pasted content to save as a UTF-8 file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Host coordinate owned by the account's model provider. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Login identifying the provider-owned account. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// A single changed file and its unified diff. +/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. +/// The gh-cli variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspaceDiffFileChange +public partial class SettableAuthInfoGhCli : SettableAuthInfo { - /// Type of change represented by this file diff. - [JsonPropertyName("changeType")] - public WorkspaceDiffFileChangeType ChangeType { get; set; } + /// + [JsonIgnore] + public override string Type => "gh-cli"; - /// Unified diff content for the file. Empty when the diff was truncated. - [JsonPropertyName("diff")] - public string Diff { get; set; } = string.Empty; + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Whether the diff content was omitted because it exceeded the per-file size limit. - [JsonPropertyName("isTruncated")] - public bool? IsTruncated { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Original file path for renamed files. - [JsonPropertyName("oldPath")] - public string? OldPath { get; set; } + /// User login as reported by `gh auth status`. + [JsonPropertyName("login")] + public required string Login { get; set; } - /// Path to the changed file, relative to the workspace root when the file lives under it. A file changed outside the workspace root keeps a `../`-relative path, or an absolute path when no relative path exists (for example a different Windows drive). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// The token returned by `gh auth token`. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// Workspace diff result for the requested mode. +/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. +/// The api-key variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspaceDiffResult +public partial class SettableAuthInfoApiKey : SettableAuthInfo { - /// Default branch used for a branch diff, when branch mode was requested. - [JsonPropertyName("baseBranch")] - public string? BaseBranch { get; set; } - - /// Changed files and their unified diffs. - [JsonPropertyName("changes")] - public IList Changes { get => field ??= []; set; } - - /// Whether the requested diff fell back to unstaged changes, either because branch diff failed or session diff was unavailable. - [JsonPropertyName("isFallback")] - public bool IsFallback { get; set; } + /// + [JsonIgnore] + public override string Type => "api-key"; - /// Effective mode used for the returned changes. - [JsonPropertyName("mode")] - public WorkspaceDiffMode Mode { get; set; } + /// The API key. Treat as a secret. + [JsonPropertyName("apiKey")] + public required string ApiKey { get; set; } - /// Diff mode requested by the client. - [JsonPropertyName("requestedMode")] - public WorkspaceDiffMode RequestedMode { get; set; } + /// 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. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Why the session diff could not be produced, when applicable. Set only when `session` mode was requested and `isFallback` is true, so a client can tell the permanent `file-change-tracking-disabled` apart from the transient `session-busy`, which the same request answers once the session settles. Never set for `unstaged` or `branch` mode, and never `unsupported-remote-session`: a remote session's captures live on its own host, so a `session`-mode diff is rejected for one rather than answered with a controller-side fallback. - [JsonPropertyName("unavailableReason")] - public HistoryRewindUnavailableReason? UnavailableReason { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// Parameters for computing a workspace diff. +/// New auth credentials to install on the session. Omit to leave credentials unchanged. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesDiffRequest +internal sealed class SessionSetCredentialsParams { - /// When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. - [JsonPropertyName("ignoreWhitespace")] - public bool? IgnoreWhitespace { get; set; } - - /// Diff mode requested by the client. - [JsonPropertyName("mode")] - public WorkspaceDiffMode Mode { get; set; } + /// 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 installs the supplied value immediately for outbound model/API requests. When the credential carries a raw token (`token`, `env`, or `gh-cli`) but no `copilotUser`, the runtime additionally re-resolves `copilotUser` server-side (best-effort, asynchronously, after the synchronous install) so plan/quota/billing metadata regains fidelity; on resolution failure the verbatim credential remains installed. It does NOT otherwise validate the credential. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit. + [JsonPropertyName("credentials")] + public SettableAuthInfo? Credentials { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Current per-window credit limit and consumption for an autopilot objective. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutopilotObjectiveCreditLimit -{ - /// Configured AI-credit cap, when one is set. - [JsonPropertyName("credits")] - public double? Credits { get; set; } - - /// Window consumption in fractional AI credits, for display. - [JsonPropertyName("creditsUsed")] - public double CreditsUsed { get; set; } - - /// Exact window consumption in non-negative integer nano-AIU, encoded as a decimal string. - [RegularExpression("^[0-9]+$")] - [JsonPropertyName("creditsUsedNanoAiu")] - public string CreditsUsedNanoAiu { get; set; } = string.Empty; -} - -/// Public, persistence-independent projection of an autopilot objective. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutopilotObjectiveState -{ - /// Optional summary recorded when the objective completed. - [JsonPropertyName("completionSummary")] - public string? CompletionSummary { get; set; } - - /// Exact lifetime AI-credit consumption in non-negative integer nano-AIU, encoded as a decimal string. - [RegularExpression("^[0-9]+$")] - [JsonPropertyName("creditCountNanoAiu")] - public string CreditCountNanoAiu { get; set; } = string.Empty; - - /// Current per-window consumption and optional cap, when a credit-tracking window is present. - [JsonPropertyName("creditLimit")] - public AutopilotObjectiveCreditLimit? CreditLimit { get; set; } - - /// Session-local objective identifier. - [JsonPropertyName("id")] - public long Id { get; set; } - - /// User-provided objective text. - [JsonPropertyName("objective")] - public string Objective { get; set; } = string.Empty; - - /// Optional reason the objective is paused. - [JsonPropertyName("pauseReason")] - public string? PauseReason { get; set; } - - /// Current normalized lifecycle status. - [JsonPropertyName("status")] - public AutopilotObjectiveStatus Status { get; set; } - - /// Number of objective turns started. - [JsonPropertyName("turnCount")] - public long TurnCount { get; set; } -} - -/// Canonical runtime state for the session's current autopilot objective. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutopilotObjectiveGetStateResult -{ - /// Current objective state, or `null` when the session has no objective. - [JsonPropertyName("state")] - public AutopilotObjectiveState? State { get; set; } -} - /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAutopilotObjectiveGetStateRequest +internal sealed class SessionGitHubAuthGetCurrentAuthInfoRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Characters that, when typed in the composer, should trigger a `completions.request`. Empty when the session has no host-driven completions (e.g. local sessions, or a relay host that does not advertise `completionTriggerCharacters`). +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CompletionsGetTriggerCharactersResult +internal sealed class SessionGitHubAuthGetAllAuthAvailableRequest { - /// Trigger characters advertised by the host (e.g. `["@", "#"]`). Empty disables host-driven completions for the session. - [JsonPropertyName("triggerCharacters")] - public IList TriggerCharacters { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCompletionsGetTriggerCharactersRequest +internal sealed class SessionGitHubAuthRefreshCopilotUserRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A single host-driven completion. Accepting an item replaces `[rangeStart, rangeEnd)` (UTF-16 code units) in the composer with `insertText`; when the range is absent, the active token around the cursor is replaced. +/// Internal GitHub login parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionCompletionItem +internal sealed class SessionAuthLoginRequest { - /// Text spliced into the composer when the item is accepted. - [JsonPropertyName("insertText")] - public string InsertText { get; set; } = string.Empty; - - /// Render-kind hint for the picker row (e.g. `"document"`, `"directory"`), derived from the host's display kind. - [JsonPropertyName("kind")] - public string? Kind { get; set; } - - /// Primary display label for the picker row. Falls back to `insertText` when absent. - [JsonPropertyName("label")] - public string? Label { get; set; } - - /// End (exclusive) of the replacement range in `text`, in UTF-16 code units. - [JsonPropertyName("rangeEnd")] - public long? RangeEnd { get; set; } - - /// Start of the replacement range in `text`, in UTF-16 code units. - [JsonPropertyName("rangeStart")] - public long? RangeStart { get; set; } -} + /// GitHub host URL. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; -/// Host-driven completion items for the current composer input. Empty when the host returns no items or does not support completions. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CompletionsRequestResult -{ - /// Completion items in host-ranked order. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } -} + /// GitHub login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; -/// Request host-driven completions for the current composer input. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CompletionsRequestRequest -{ - /// Cursor offset within `text`, in UTF-16 code units. - [JsonPropertyName("offset")] - public long Offset { get; set; } + /// Whether to persist the token after login. + [JsonPropertyName("persist")] + public bool? Persist { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// The full composed composer input. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; + /// GitHub authentication token. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// Instruction sources loaded for the session, in merge order. +/// Parameters for switching the session's active authentication. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionsGetSourcesResult +internal sealed class SessionAuthSwitchRequest { - /// Instruction sources for the session. - [JsonPropertyName("sources")] - public IList Sources { get => field ??= []; set; } -} + /// Authentication information to activate. + [JsonPropertyName("authInfo")] + public AuthInfo AuthInfo { get => field ??= new(); set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionInstructionsGetSourcesRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Optional token paired with the authentication information. + [JsonPropertyName("token")] + public string? Token { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionInstructionsReloadRequest +internal sealed class SessionGitHubAuthLogoutRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of one customization reload component. +/// Parameters identifying a GitHub authentication to log out. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CustomizationReloadOutcome +internal sealed class SessionAuthLogoutUserRequest { - /// Reason for a skipped component or description of a failure, when available. - [JsonPropertyName("detail")] - public string? Detail { get; set; } - - /// Whether the component reloaded, was skipped, or failed. - [JsonPropertyName("status")] - public CustomizationReloadStatus Status { get; set; } + /// Authentication information to log out. + [JsonPropertyName("authInfo")] + public AuthInfo AuthInfo { get => field ??= new(); set; } - /// Component whose reload was attempted or skipped. - [JsonPropertyName("subsystem")] - public CustomizationReloadSubsystem Subsystem { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Results of reloading discovered session customizations. Inspect outcomes for reloaded, skipped, or failed subsystems; a rejection may follow partial mutation. Changes to the model-facing prompt and tools apply on the next turn. +/// Validation error from an authentication attempt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CustomizationsReloadResult +public sealed class AuthValidationError { - /// Errors from any component that could not be refreshed. - [JsonPropertyName("errors")] - public IList Errors { get => field ??= []; set; } - - /// Outcome of each component in reload order; a skipped component was not configured or loaded. - [JsonPropertyName("outcomes")] - public IList Outcomes { get => field ??= []; set; } + /// Optional message returned by GitHub. + [JsonPropertyName("githubMessage")] + public string? GitHubMessage { get; set; } - /// Warnings from skill discovery. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// Authentication validation error message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCustomizationsReloadRequest +internal sealed class SessionGitHubAuthLastAuthErrorsRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether fleet mode was successfully activated. +/// The enumerated collection, keyed by the same selector as the query. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class FleetStartResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthEnumerateValueAccounts), "accounts")] +[JsonDerivedType(typeof(AuthEnumerateValueProviders), "providers")] +public partial class AuthEnumerateValue { - /// Whether fleet mode was successfully activated. - [JsonPropertyName("started")] - public bool Started { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. + +/// One signed-in account in the roster forest. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FleetStartRequest +public sealed class AccountStatus { - /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the fleet request. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } + /// Whether this is the active account. + [JsonPropertyName("active")] + public bool Active { get; set; } - /// If false, this request will not trigger a Premium Request Unit charge. User requests default to billable. - [JsonInclude] - [JsonPropertyName("billable")] - internal bool? Billable { get; set; } + /// Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. + [JsonPropertyName("authSource")] + public string? AuthSource { get; set; } - /// Optional user prompt to combine with fleet instructions. - [JsonPropertyName("prompt")] - public string? Prompt { get; set; } + /// Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. + [JsonPropertyName("derivedFrom")] + public string? DerivedFrom { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Authentication host URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// If true, await completion of the agentic loop for this fleet request before returning. Defaults to false. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } + /// The provider kind of this account. + [JsonPropertyName("kind")] + public AccountKind Kind { get; set; } + + /// Authenticated login/username. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; + + /// Opaque selection id used to switch to, or log out, this account. + [JsonPropertyName("selectionId")] + public string SelectionId { get; set; } = string.Empty; } -/// Agents available to the session. +/// The accounts variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentList +public partial class AuthEnumerateValueAccounts : AuthEnumerateValue { - /// Available agents. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "accounts"; + + /// The signed-in account forest; empty when not logged in. + [JsonPropertyName("items")] + public required IList Items { get; set; } } -/// RPC data type for SessionAgentList operations. +/// A provider offered for interactive login. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionAgentListRequest +public sealed class ProviderDescriptor { - /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. - [JsonPropertyName("includeBuiltInAgents")] - public bool? IncludeBuiltInAgents { get; set; } + /// Whether this provider is currently available to sign in with. + [JsonPropertyName("available")] + public bool Available { get; set; } - /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. - [JsonPropertyName("includePrompt")] - public bool? IncludePrompt { get; set; } + /// The neutral provider kind. + [JsonPropertyName("kind")] + public LoginProviderKind Kind { get; set; } + + /// Human-readable menu label, owned by the runtime so every consumer renders identical text. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; } -/// RPC data type for SessionAgentListRequestWithSession operations. +/// The providers variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentListRequestWithSession +public partial class AuthEnumerateValueProviders : AuthEnumerateValue { - /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. - [JsonPropertyName("includeBuiltInAgents")] - public bool? IncludeBuiltInAgents { get; set; } - - /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. - [JsonPropertyName("includePrompt")] - public bool? IncludePrompt { get; set; } + /// + [JsonIgnore] + public override string Kind => "providers"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The providers offered for interactive login. + [JsonPropertyName("items")] + public required IList Items { get; set; } } -/// An in-memory authored prompt override for an available agent. +/// Selects which accounts collection to enumerate. A no-arg selector is the empty-payload variant. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentSetPromptRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthEnumerateQueryAccounts), "accounts")] +[JsonDerivedType(typeof(AuthEnumerateQueryProviders), "providers")] +public partial class AuthEnumerateQuery { - /// Stable effective agent id. Plugin namespace separators are normalized. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Replacement authored prompt. Empty text is valid. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; +/// The accounts variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthEnumerateQueryAccounts : AuthEnumerateQuery +{ + /// + [JsonIgnore] + public override string Kind => "accounts"; } -/// The currently selected custom agent, or null when using the default agent. +/// The providers variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentGetCurrentResult +public partial class AuthEnumerateQueryProviders : AuthEnumerateQuery { - /// Currently selected custom agent, or null if using the default agent. - [JsonPropertyName("agent")] - public AgentInfo? Agent { get; set; } + /// + [JsonIgnore] + public override string Kind => "providers"; + + /// Whether an interactive Entra broker is available on the host; gates Entra availability in the returned list. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("brokerAvailable")] + public bool? BrokerAvailable { get; set; } } -/// Identifies the target session. +/// Enumerate request carrying the typed collection query. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentGetCurrentRequest +internal sealed class AccountsEnumerateRequest { + /// Which typed accounts collection to enumerate. + [JsonPropertyName("query")] + public AuthEnumerateQuery Query { get => field ??= new(); set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The newly selected custom agent. +/// The read result, keyed by the same selector as the query. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentSelectResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthReadValueActiveAccount), "activeAccount")] +[JsonDerivedType(typeof(AuthReadValueStatus), "status")] +[JsonDerivedType(typeof(AuthReadValueLastErrors), "lastErrors")] +public partial class AuthReadValue { - /// The newly selected custom agent. - [JsonPropertyName("agent")] - public AgentInfo Agent { get => field ??= new(); set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Name of the custom agent to select for subsequent turns. + +/// The activeAccount variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentSelectRequest +public partial class AuthReadValueActiveAccount : AuthReadValue { - /// Name of the custom agent to select. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "activeAccount"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The active account, or absent when not logged in. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("account")] + public AccountStatus? Account { get; set; } + + /// Credential-free identity metadata for the active account, including resolved Copilot user information when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("authInfo")] + public AuthIdentity? AuthInfo { get; set; } } -/// Identifies the target session. +/// Neutral authentication status summary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentDeselectRequest +public sealed class AuthStatusDto { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Number of signed-in accounts in the roster. + [JsonPropertyName("accountCount")] + public long AccountCount { get; set; } + + /// Active account host, if authenticated. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("activeHost")] + public string? ActiveHost { get; set; } + + /// Active account login, if authenticated. + [JsonPropertyName("activeLogin")] + public string? ActiveLogin { get; set; } + + /// Copilot plan tier of the active account, if known. + [JsonPropertyName("copilotPlan")] + public string? CopilotPlan { get; set; } + + /// Whether the session has resolved authentication. + [JsonPropertyName("isAuthenticated")] + public bool IsAuthenticated { get; set; } } -/// Custom agents available to the session after reloading definitions from disk. +/// The status variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentReloadResult +public partial class AuthReadValueStatus : AuthReadValue { - /// Reloaded custom agents. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "status"; + + /// The neutral authentication status summary. + [JsonPropertyName("status")] + public required AuthStatusDto Status { get; set; } } -/// Identifies the target session. +/// The lastErrors variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentReloadRequest +public partial class AuthReadValueLastErrors : AuthReadValue { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "lastErrors"; + + /// Validation errors from the most recent authentication attempt. + [JsonPropertyName("errors")] + public required IList Errors { get; set; } } -/// Identifier assigned to the newly started background agent task. +/// Selects which typed accounts datum to read. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksStartAgentResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthReadQueryActiveAccount), "activeAccount")] +[JsonDerivedType(typeof(AuthReadQueryStatus), "status")] +[JsonDerivedType(typeof(AuthReadQueryLastErrors), "lastErrors")] +public partial class AuthReadQuery { - /// Generated agent ID for the background task. - [JsonPropertyName("agentId")] - public string AgentId { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Agent type, prompt, name, and optional description and model override for the new task. + +/// The activeAccount variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksStartAgentRequest +public partial class AuthReadQueryActiveAccount : AuthReadQuery { - /// Type of agent to start (e.g., 'explore', 'task', 'general-purpose'). - [JsonPropertyName("agentType")] - public string AgentType { get; set; } = string.Empty; - - /// Short description of the task. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// + [JsonIgnore] + public override string Kind => "activeAccount"; +} - /// Optional model override. - [JsonPropertyName("model")] - public string? Model { get; set; } +/// The status variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthReadQueryStatus : AuthReadQuery +{ + /// + [JsonIgnore] + public override string Kind => "status"; +} - /// Friendly, non-unique name used when displaying the agent. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// The lastErrors variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthReadQueryLastErrors : AuthReadQuery +{ + /// + [JsonIgnore] + public override string Kind => "lastErrors"; +} - /// Task prompt for the agent. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; +/// Read request carrying the typed datum query. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountsGetRequest +{ + /// Which typed accounts datum to read. + [JsonPropertyName("query")] + public AuthReadQuery Query { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Tracked task union returned by task APIs, containing an agent, client, or shell task. -/// Polymorphic base type discriminated by type. +/// Result of a non-interactive accounts mutation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AuthWriteResult +{ + /// For a logout, whether other signed-in accounts remain. + [JsonPropertyName("moreUsers")] + public bool? MoreUsers { get; set; } + + /// Whether the mutation was applied. + [JsonPropertyName("ok")] + public bool Ok { get; set; } +} + +/// One non-interactive accounts mutation command (the selector is fused with its typed args). +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", + TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(TaskInfoAgent), "agent")] -[JsonDerivedType(typeof(TaskInfoClient), "client")] -[JsonDerivedType(typeof(TaskInfoShell), "shell")] -public partial class TaskInfo +[JsonDerivedType(typeof(AuthWriteSwitchActive), "switchActive")] +[JsonDerivedType(typeof(AuthWriteLogout), "logout")] +[JsonDerivedType(typeof(AuthWriteSetCredentials), "setCredentials")] +public partial class AuthWrite { /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Tracked background agent task metadata, including IDs, status, timing, agent type, prompt, model, result, and latest response. -/// The agent variant of . +/// The switchActive variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskInfoAgent : TaskInfo +public partial class AuthWriteSwitchActive : AuthWrite { /// [JsonIgnore] - public override string Type => "agent"; + public override string Kind => "switchActive"; - /// ISO 8601 timestamp when the current active period began. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("activeStartedAt")] - public DateTimeOffset? ActiveStartedAt { get; set; } + /// Opaque selection id of the account to make active. + [JsonPropertyName("selectionId")] + public required string SelectionId { get; set; } +} - /// Accumulated active execution time in milliseconds. - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] +/// The logout variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthWriteLogout : AuthWrite +{ + /// + [JsonIgnore] + public override string Kind => "logout"; + + /// Opaque selection id of the account to log out; absent logs out the active account. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("activeTimeMs")] - public TimeSpan? ActiveTime { get; set; } + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } +} - /// Type of agent running this task. - [JsonPropertyName("agentType")] - public required string AgentType { get; set; } +/// The setCredentials variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthWriteSetCredentials : AuthWrite +{ + /// + [JsonIgnore] + public override string Kind => "setCredentials"; - /// Whether the task is currently in the original sync wait and can be moved to background mode. False once it is already backgrounded, idle, finished, or no longer has a promotable sync waiter. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("canPromoteToBackground")] - public bool? CanPromoteToBackground { get; set; } + /// Authentication host URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public required string Host { get; set; } - /// ISO 8601 timestamp when the task finished. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } + /// Login/username for the credential. + [JsonPropertyName("login")] + public required string Login { get; set; } - /// Short description of the task. - [JsonPropertyName("description")] - public required string Description { get; set; } + /// GitHub authentication token to install. + [JsonPropertyName("token")] + public required string Token { get; set; } +} - /// Friendly, non-unique name intended for display. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } +/// Mutation request carrying the typed write command. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountsSetRequest +{ + /// The non-interactive mutation command to apply. + [JsonPropertyName("command")] + public AuthWrite Command { get => field ??= new(); set; } - /// Error message when the task failed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether task execution is synchronously awaited or managed in the background. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("executionMode")] - public TaskExecutionMode? ExecutionMode { get; set; } +/// One step in an interactive login flow. The consumer acts on the step and calls advance to proceed. Browser-open is encoded as two distinct steps by design: `open-url` is CONSUMER-driven (the provider surfaces the authorize URL and the consumer opens it — github.com/GHEC web), while `needs-interaction` is PROVIDER-driven (the provider opens the browser or broker UI itself and does not surface a URL — Entra). +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthLoginStepOpenUrl), "open-url")] +[JsonDerivedType(typeof(AuthLoginStepInputRequired), "input-required")] +[JsonDerivedType(typeof(AuthLoginStepAwaiting), "awaiting")] +[JsonDerivedType(typeof(AuthLoginStepNeedsInteraction), "needs-interaction")] +[JsonDerivedType(typeof(AuthLoginStepCompleted), "completed")] +[JsonDerivedType(typeof(AuthLoginStepError), "error")] +public partial class AuthLoginStep +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Unique task identifier. - [JsonPropertyName("id")] - public required string Id { get; set; } - /// ISO 8601 timestamp when the agent entered idle state. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("idleSince")] - public DateTimeOffset? IdleSince { get; set; } +/// The open-url variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepOpenUrl : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "open-url"; - /// Most recent response text from the agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("latestResponse")] - public string? LatestResponse { get; set; } + /// Authorize URL the consumer should open in a browser (consumer-driven browser-open). + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Requested model override for the task when specified. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } +/// The input-required variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepInputRequired : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "input-required"; - /// Most recent prompt delivered to the agent. Updated whenever the agent receives a follow-up message. + /// Prompt for the value the provider needs; the consumer supplies it as advance input (e.g. a GitHub Enterprise Cloud host, *.ghe.com). [JsonPropertyName("prompt")] public required string Prompt { get; set; } +} - /// Runtime model resolved for the task when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resolvedModel")] - public string? ResolvedModel { get; set; } - - /// Result text from the task when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("result")] - public string? Result { get; set; } - - /// ISO 8601 timestamp when the task was started. - [JsonPropertyName("startedAt")] - public required DateTimeOffset StartedAt { get; set; } - - /// Current lifecycle status of the task. - [JsonPropertyName("status")] - public required TaskStatus Status { get; set; } +/// The awaiting variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepAwaiting : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "awaiting"; +} - /// Tool call ID associated with this agent task. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } +/// The needs-interaction variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepNeedsInteraction : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "needs-interaction"; } -/// Public owner attribution for a client-owned task. Identifiers are opaque and never authorize requests. +/// A credential-free account choice after sign-in. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskClientOwner +public sealed class AuthLoginAccount { - /// ISO 8601 timestamp when the bound join disconnected. - [JsonPropertyName("disconnectedAt")] - public DateTimeOffset? DisconnectedAt { get; set; } + /// Host coordinate owned by the selected account's provider. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Display-only owner name. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } - - /// Opaque identity of the currently or most recently bound session join. - [JsonPropertyName("joinId")] - public string JoinId { get; set; } = string.Empty; - - /// Class of the task owner. + /// Provider kind that owns this account choice. [JsonPropertyName("kind")] - public TaskClientOwnerKind Kind { get; set; } - - /// Opaque session-scoped participant identity. - [JsonPropertyName("participantId")] - public string ParticipantId { get; set; } = string.Empty; + public AccountKind Kind { get; set; } - /// Whether this task's bound join is currently connected. - [JsonPropertyName("presence")] - public TaskClientOwnerPresence Presence { get; set; } + /// Human-readable login for the account choice. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Display-only owner source. - [JsonPropertyName("source")] - public string? Source { get; set; } + /// Opaque identifier supplied to the next login step to select this account. + [JsonPropertyName("selectionId")] + public string SelectionId { get; set; } = string.Empty; } -/// Tracked client-owned task metadata. -/// The client variant of . +/// Result of an interactive login flow. Pending consent or account selection is not terminal. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskInfoClient : TaskInfo +public sealed class AuthLoginResultDto { - /// - [JsonIgnore] - public override string Type => "client"; - - /// ISO 8601 timestamp when the current active segment started. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("activeStartedAt")] - public DateTimeOffset? ActiveStartedAt { get; set; } - - /// Accumulated active execution time in milliseconds. - [JsonPropertyName("activeTimeMs")] - public required long ActiveTimeMs { get; set; } - - /// Whether the currently bound owner can receive a cancellation request. - [JsonPropertyName("canCancel")] - public required bool CanCancel { get; set; } - - /// Human-readable reason for terminal cancellation. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cancellationReason")] - public string? CancellationReason { get; set; } - - /// Owner-scoped registration and reclaim key. - [JsonPropertyName("clientTaskId")] - public required string ClientTaskId { get; set; } - - /// ISO 8601 timestamp when the task reached a terminal status. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } - - /// Task description. - [JsonPropertyName("description")] - public required string Description { get; set; } - - /// Optional task display name. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } - - /// Human-readable terminal failure message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Optional owner-supplied terminal failure code. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("errorCode")] - public string? ErrorCode { get; set; } - - /// Execution mode, which is always background for client-owned tasks. - [JsonPropertyName("executionMode")] - public required TaskClientExecutionMode ExecutionMode { get; set; } - - /// Canonical runtime-generated task identifier. - [JsonPropertyName("id")] - public required string Id { get; set; } - - /// ISO 8601 timestamp when the connected owner entered idle status. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("idleSince")] - public DateTimeOffset? IdleSince { get; set; } - - /// ISO 8601 timestamp of the most recent orphan transition. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("orphanedAt")] - public DateTimeOffset? OrphanedAt { get; set; } + /// Available accounts when sign-in is awaiting account selection, ordered with Microsoft 365 first. + [JsonPropertyName("accounts")] + public IList? Accounts { get; set; } - /// Public attribution and presence for the task owner. - [JsonPropertyName("owner")] - public required TaskClientOwner Owner { get; set; } - - /// ISO 8601 timestamp of the most recent successful reclaim. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reclaimedAt")] - public DateTimeOffset? ReclaimedAt { get; set; } - - /// Opaque successful terminal result supplied by the task owner. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } - - /// Sequence number of the latest accepted owner update. - [JsonPropertyName("sequence")] - public required long Sequence { get; set; } + /// Host that was signed in, when completed. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public string? Host { get; set; } - /// ISO 8601 timestamp when the task started. - [JsonPropertyName("startedAt")] - public required DateTimeOffset StartedAt { get; set; } + /// Login that was signed in, when completed. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Client task lifecycle status. + /// Current disposition of the login, including pending user decisions. [JsonPropertyName("status")] - public required TaskClientStatus Status { get; set; } - - /// ISO 8601 timestamp of the latest accepted lifecycle change. - [JsonPropertyName("updatedAt")] - public required DateTimeOffset UpdatedAt { get; set; } + public AuthLoginResultStatus Status { get; set; } } -/// Tracked shell task metadata, including ID, command, status, timing, attachment/execution mode, log path, and PID. -/// The shell variant of . +/// The completed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskInfoShell : TaskInfo +public partial class AuthLoginStepCompleted : AuthLoginStep { /// [JsonIgnore] - public override string Type => "shell"; - - /// Whether the shell runs inside a managed PTY session or as an independent background process. - [JsonPropertyName("attachmentMode")] - public required TaskShellInfoAttachmentMode AttachmentMode { get; set; } - - /// Whether this shell task can be promoted to background mode. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("canPromoteToBackground")] - public bool? CanPromoteToBackground { get; set; } - - /// Command being executed. - [JsonPropertyName("command")] - public required string Command { get; set; } - - /// ISO 8601 timestamp when the task finished. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } - - /// Short description of the task. - [JsonPropertyName("description")] - public required string Description { get; set; } - - /// Whether task execution is synchronously awaited or managed in the background. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("executionMode")] - public TaskExecutionMode? ExecutionMode { get; set; } - - /// Unique task identifier. - [JsonPropertyName("id")] - public required string Id { get; set; } - - /// Path to the detached shell log, when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("logPath")] - public string? LogPath { get; set; } + public override string Kind => "completed"; - /// Process ID when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pid")] - public long? Pid { get; set; } + /// Login result. When status is needs-plaintext-consent or needs-account-selection, advance with the user's decision to continue. + [JsonPropertyName("result")] + public required AuthLoginResultDto Result { get; set; } +} - /// ISO 8601 timestamp when the task was started. - [JsonPropertyName("startedAt")] - public required DateTimeOffset StartedAt { get; set; } +/// The error variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepError : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "error"; - /// Current lifecycle status of the task. - [JsonPropertyName("status")] - public required TaskStatus Status { get; set; } + /// Human-readable failure message. + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Background tasks currently tracked by the session. +/// A started login flow: its opaque id and first step. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskList +public sealed class AuthLoginBegun { - /// Currently tracked tasks. - [JsonPropertyName("tasks")] - public IList Tasks { get => field ??= []; set; } + /// Opaque flow id used to advance or cancel this login. + [JsonPropertyName("flowId")] + public string FlowId { get; set; } = string.Empty; + + /// The first step of the flow. + [JsonPropertyName("step")] + public AuthLoginStep Step { get => field ??= new(); set; } } -/// Identifies the target session. +/// Begin an interactive login flow for a provider kind. Dispatch is kind-only. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksListRequest +internal sealed class AuthLoginBeginRequest { + /// The provider kind to sign in with. + [JsonPropertyName("kind")] + public LoginProviderKind Kind { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Tracked client-owned task metadata. +/// Advance an in-flight login flow, optionally fulfilling an input-required step. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskClientInfo +internal sealed class AuthLoginAdvanceRequest { - /// ISO 8601 timestamp when the current active segment started. - [JsonPropertyName("activeStartedAt")] - public DateTimeOffset? ActiveStartedAt { get; set; } - - /// Accumulated active execution time in milliseconds. - [JsonPropertyName("activeTimeMs")] - public long ActiveTimeMs { get; set; } - - /// Whether the currently bound owner can receive a cancellation request. - [JsonPropertyName("canCancel")] - public bool CanCancel { get; set; } - - /// Human-readable reason for terminal cancellation. - [JsonPropertyName("cancellationReason")] - public string? CancellationReason { get; set; } - - /// Owner-scoped registration and reclaim key. - [JsonPropertyName("clientTaskId")] - public string ClientTaskId { get; set; } = string.Empty; - - /// ISO 8601 timestamp when the task reached a terminal status. - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } - - /// Task description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Optional task display name. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } - - /// Human-readable terminal failure message. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Optional owner-supplied terminal failure code. - [JsonPropertyName("errorCode")] - public string? ErrorCode { get; set; } - - /// Execution mode, which is always background for client-owned tasks. - [JsonPropertyName("executionMode")] - public TaskClientExecutionMode ExecutionMode { get; set; } - - /// Canonical runtime-generated task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// ISO 8601 timestamp when the connected owner entered idle status. - [JsonPropertyName("idleSince")] - public DateTimeOffset? IdleSince { get; set; } - - /// ISO 8601 timestamp of the most recent orphan transition. - [JsonPropertyName("orphanedAt")] - public DateTimeOffset? OrphanedAt { get; set; } - - /// Public attribution and presence for the task owner. - [JsonPropertyName("owner")] - public TaskClientOwner Owner { get => field ??= new(); set; } - - /// ISO 8601 timestamp of the most recent successful reclaim. - [JsonPropertyName("reclaimedAt")] - public DateTimeOffset? ReclaimedAt { get; set; } - - /// Opaque successful terminal result supplied by the task owner. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } - - /// Sequence number of the latest accepted owner update. - [JsonPropertyName("sequence")] - public long Sequence { get; set; } + /// Opaque flow id from begin. + [JsonPropertyName("flowId")] + public string FlowId { get; set; } = string.Empty; - /// ISO 8601 timestamp when the task started. - [JsonPropertyName("startedAt")] - public DateTimeOffset StartedAt { get; set; } + /// Neutral input fulfilling a preceding input-required step (e.g. a GHEC host); ignored otherwise. + [JsonPropertyName("input")] + public string? Input { get; set; } - /// Client task lifecycle status. - [JsonPropertyName("status")] - public TaskClientStatus Status { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Task kind. - [JsonPropertyName("type")] - public TaskClientType Type { get; set; } +/// Cancel an in-flight login flow. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AuthLoginCancelRequest +{ + /// Opaque flow id from begin. + [JsonPropertyName("flowId")] + public string FlowId { get; set; } = string.Empty; - /// ISO 8601 timestamp of the latest accepted lifecycle change. - [JsonPropertyName("updatedAt")] - public DateTimeOffset UpdatedAt { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Result of registering or reclaiming a client-owned task. +/// A file included in the session debug bundle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksRegisterResult +public sealed class DebugCollectLogsCollectedEntry { - /// True only when this invocation created a new task. - [JsonPropertyName("created")] - public bool Created { get; set; } + /// Relative path of the file in the staged bundle/archive. + [JsonPropertyName("bundlePath")] + public string BundlePath { get; set; } = string.Empty; - /// True only when this invocation reclaimed an orphaned task. - [JsonPropertyName("reclaimed")] - public bool Reclaimed { get; set; } + /// Redacted output size in bytes. + [JsonPropertyName("sizeBytes")] + public long SizeBytes { get; set; } - /// Authoritative registered or reclaimed task. - [JsonPropertyName("task")] - public TaskClientInfo Task { get => field ??= new(); set; } + /// Source category for this entry. + [JsonPropertyName("source")] + public DebugCollectLogsSource Source { get; set; } } -/// Registers or reclaims a client-owned task. +/// An optional debug bundle entry that could not be included. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksRegisterRequest +public sealed class DebugCollectLogsSkippedEntry { - /// Whether the owner supports runtime cancellation requests. - [JsonPropertyName("cancellable")] - public bool Cancellable { get; set; } + /// Relative path requested for this bundle entry. + [JsonPropertyName("bundlePath")] + public string BundlePath { get; set; } = string.Empty; - /// Owner-scoped idempotency key used for registration and reclaim. - [JsonPropertyName("clientTaskId")] - public string ClientTaskId { get; set; } = string.Empty; + /// Server-local source path that could not be read. + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Human-readable description of the external work. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Reason the entry was skipped. + [JsonPropertyName("reason")] + public string Reason { get; set; } = string.Empty; +} - /// Optional short display name for the external work. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } +/// Result of collecting a session debug bundle. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DebugCollectLogsResult +{ + /// Files included in the bundle. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } - /// Expected current sequence for idempotent registration or orphan reclaim. - [JsonPropertyName("expectedSequence")] - public long? ExpectedSequence { get; set; } + /// Destination kind that was written. + [JsonPropertyName("kind")] + public DebugCollectLogsResultKind Kind { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Actual archive path or staging directory path written. This may differ from the requested path when no-overwrite suffixing or fallback-to-temp-directory was needed. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Task kind. - [JsonPropertyName("type")] - public TaskClientType Type { get; set; } + /// Optional files or directories that could not be included. + [JsonPropertyName("skippedEntries")] + public IList? SkippedEntries { get; set; } } -/// Result of publishing a client-owned task update. +/// A caller-provided server-local file or directory to include in the debug bundle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksUpdateResult +public sealed class DebugCollectLogsEntry { - /// Whether this invocation changed task state. - [JsonPropertyName("applied")] - public bool Applied { get; set; } + /// Relative path to use inside the staged bundle/archive. + [JsonPropertyName("bundlePath")] + public string BundlePath { get; set; } = string.Empty; - /// Whether this invocation repeated the latest accepted update. - [JsonPropertyName("duplicate")] - public bool Duplicate { get; set; } + /// Kind of source path to include. + [JsonPropertyName("kind")] + public DebugCollectLogsEntryKind Kind { get; set; } - /// Authoritative task after processing the update. - [JsonPropertyName("task")] - public TaskClientInfo Task { get => field ??= new(); set; } + /// Server-local source path to read. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// How text content from this entry should be redacted. Defaults to plain-text. With none, no redaction is applied; the caller must ensure any necessary redaction is performed before this call. + [JsonPropertyName("redaction")] + public DebugCollectLogsRedaction? Redaction { get; set; } + + /// When true, collection fails if this entry cannot be read. Defaults to false, which records the entry in `skippedEntries`. + [JsonPropertyName("required")] + public bool? Required { get; set; } } -/// Progress or terminal update for a client-owned task. +/// Destination for the session debug bundle. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(TaskClientUpdateProgress), "progress")] -[JsonDerivedType(typeof(TaskClientUpdateCompleted), "completed")] -[JsonDerivedType(typeof(TaskClientUpdateFailed), "failed")] -[JsonDerivedType(typeof(TaskClientUpdateCancelled), "cancelled")] -public partial class TaskClientUpdate +[JsonDerivedType(typeof(DebugCollectLogsDestinationArchive), "archive")] +[JsonDerivedType(typeof(DebugCollectLogsDestinationDirectory), "directory")] +public partial class DebugCollectLogsDestination { /// The type discriminator. [JsonPropertyName("kind")] @@ -14910,5518 +14243,10850 @@ public partial class TaskClientUpdate } -/// Publishes nonterminal progress for a running or idle client task. -/// The progress variant of . +/// The archive variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateProgress : TaskClientUpdate +public partial class DebugCollectLogsDestinationArchive : DebugCollectLogsDestination { /// [JsonIgnore] - public override string Kind => "progress"; - - /// Optional progress message appended to recent activity when nonempty. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } - - /// Optional completion percentage; null clears the current percentage. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("percentage")] - public double? Percentage { get; set; } + public override string Kind => "archive"; - /// Optional progress phase; null clears the current phase. + /// When true, create the archive atomically without overwriting an existing file by appending ` (N)` before the extension as needed. Defaults to false. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("phase")] - public string? Phase { get; set; } + [JsonPropertyName("noOverwrite")] + public bool? NoOverwrite { get; set; } - /// Optional active status transition. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("status")] - public TaskClientActiveStatus? Status { get; set; } + /// Absolute or server-relative path for the .tgz archive to create. + [JsonPropertyName("outputPath")] + public required string OutputPath { get; set; } } -/// Reports successful terminal completion. -/// The completed variant of . +/// The directory variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateCompleted : TaskClientUpdate +public partial class DebugCollectLogsDestinationDirectory : DebugCollectLogsDestination { /// [JsonIgnore] - public override string Kind => "completed"; - - /// Optional final progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + public override string Kind => "directory"; - /// Optional opaque successful terminal result. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + /// Directory where files should be staged. The directory is created if needed. + [JsonPropertyName("outputDirectory")] + public required string OutputDirectory { get; set; } } -/// Reports terminal failure. -/// The failed variant of . +/// Built-in session diagnostics to include in the bundle. Omitted fields default to true. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateFailed : TaskClientUpdate +public sealed class DebugCollectLogsInclude { - /// - [JsonIgnore] - public override string Kind => "failed"; + /// Server-local path to the current process log. When set, it is included as `process.log` and its directory is searched for prior logs from the same session. + [JsonPropertyName("currentProcessLogPath")] + public string? CurrentProcessLogPath { get; set; } - /// Optional owner-supplied terminal failure code. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("code")] - public string? Code { get; set; } + /// Include the session event log (`events.jsonl`). Defaults to true. + [JsonPropertyName("events")] + public bool? Events { get; set; } - /// Human-readable terminal failure message. - [JsonPropertyName("error")] - public required string Error { get; set; } + /// Server-local path to the session's events.jsonl file. Internal callers normally omit this and let the runtime derive it from the session. + [JsonPropertyName("eventsPath")] + public string? EventsPath { get; set; } - /// Optional final progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } -} + /// Maximum number of previous process logs to include. Defaults to 5. + [JsonPropertyName("previousProcessLogLimit")] + public long? PreviousProcessLogLimit { get; set; } -/// Reports terminal cancellation after external work stopped. -/// The cancelled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateCancelled : TaskClientUpdate -{ - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// Server-local process log directory to search when `currentProcessLogPath` is unavailable, useful for collecting logs for inactive sessions. + [JsonPropertyName("processLogDirectory")] + public string? ProcessLogDirectory { get; set; } - /// Optional final progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Include process logs for the session. Defaults to true. + [JsonPropertyName("processLogs")] + public bool? ProcessLogs { get; set; } - /// Optional human-readable cancellation reason. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Include interactive shell logs written under the session's `shell-logs` directory. Defaults to true. + [JsonPropertyName("shellLogs")] + public bool? ShellLogs { get; set; } } -/// Updates a client-owned task. +/// Options for collecting a session debug bundle with configurable redaction. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksUpdateRequest +internal sealed class DebugCollectLogsRequest { - /// Canonical runtime-generated task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Caller-provided server-local files or directories to include in addition to the runtime's built-in session diagnostics. This lets host applications add their own diagnostics without changing the API shape. + [JsonPropertyName("additionalEntries")] + public IList? AdditionalEntries { get; set; } - /// Owner update sequence to apply. - [JsonPropertyName("sequence")] - public long Sequence { get; set; } + /// Where the bundle should be written. Use `archive` to produce a .tgz, or `directory` to stage files for caller-managed upload/post-processing. + [JsonPropertyName("destination")] + public DebugCollectLogsDestination Destination { get => field ??= new(); set; } + + /// Which built-in session diagnostics to include. Omitted fields default to true. + [JsonPropertyName("include")] + public DebugCollectLogsInclude? Include { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Progress or terminal update payload. - [JsonPropertyName("update")] - public TaskClientUpdate Update { get => field ??= new(); set; } } -/// 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. +/// Canvas action that the agent or host can invoke. To discover the input schema for a particular action, call the list_canvas_capabilities tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksRefreshResult +public sealed class CanvasAction { + /// Description of the action. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// JSON Schema for the action input. + [JsonPropertyName("inputSchema")] + public JsonElement? InputSchema { get; set; } + + /// Action name exposed by the canvas provider. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Identifies the target session. +/// Canvas available in the current session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksRefreshRequest +public sealed class DiscoveredCanvas { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Actions the agent or host may invoke on an open instance. + [JsonPropertyName("actions")] + public IList? Actions { get; set; } + + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; + + /// Short, single-sentence description shown to the agent in canvas catalogs. + [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("description")] + public string Description { get; set; } = string.Empty; + + /// Human-readable canvas name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; + + /// Owning extension display name, when available. + [JsonPropertyName("extensionName")] + public string? ExtensionName { get; set; } + + /// Host-local PNG path for the canvas icon, when supplied. + [JsonPropertyName("icon")] + public string? Icon { get; set; } + + /// JSON Schema for canvas open input. + [JsonPropertyName("inputSchema")] + public JsonElement? InputSchema { get; set; } } -/// Wait until all in-flight background tasks (agents + shells) and any follow-up 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). +/// Declared canvases available in this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksWaitForPendingResult +public sealed class CanvasList { + /// Declared canvases available in this session. + [JsonPropertyName("canvases")] + public IList Canvases { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksWaitForPendingRequest +internal sealed class SessionCanvasListRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. -/// Polymorphic base type discriminated by type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(TaskProgressAgent), "agent")] -[JsonDerivedType(typeof(TaskProgressClient), "client")] -[JsonDerivedType(typeof(TaskProgressShell), "shell")] -public partial class TaskProgress -{ - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} - - -/// Timestamped display line for task progress output or recent agent activity. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskProgressLine -{ - /// Display message, e.g., "▸ bash", "✓ edit src/foo.ts". - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; - - /// ISO 8601 timestamp when this event occurred. - [JsonPropertyName("timestamp")] - public DateTimeOffset Timestamp { get; set; } -} - -/// Progress snapshot for an agent task, with recent activity lines and optional latest intent. -/// The agent variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskProgressAgent : TaskProgress -{ - /// - [JsonIgnore] - public override string Type => "agent"; - - /// The most recent intent reported by the agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("latestIntent")] - public string? LatestIntent { get; set; } - - /// Recent tool execution events converted to display lines. - [JsonPropertyName("recentActivity")] - public required IList RecentActivity { get; set; } -} - -/// Generic progress for a client-owned task. -/// The client variant of . +/// Open canvas instance snapshot. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskProgressClient : TaskProgress +public sealed class OpenCanvasInstance { - /// - [JsonIgnore] - public override string Type => "client"; + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; - /// Most recent nonempty progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("lastMessage")] - public string? LastMessage { get; set; } + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; - /// Current completion percentage from zero through one hundred. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("percentage")] - public double? Percentage { get; set; } + /// Owning extension display name, when available. + [JsonPropertyName("extensionName")] + public string? ExtensionName { get; set; } - /// Current owner-defined progress phase. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("phase")] - public string? Phase { get; set; } + /// Host-local PNG path for the canvas icon, when supplied. + [JsonPropertyName("icon")] + public string? Icon { get; set; } - /// Recent server-timestamped progress messages. - [JsonPropertyName("recentActivity")] - public required IList RecentActivity { get; set; } + /// Input supplied when the instance was opened. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } - /// Sequence number of the latest accepted owner update. - [JsonPropertyName("sequence")] - public required long Sequence { get; set; } + /// Stable caller-supplied canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; - /// Current client task lifecycle status. + /// Provider-supplied status text. [JsonPropertyName("status")] - public required TaskClientStatus Status { get; set; } - - /// ISO 8601 timestamp of the latest accepted lifecycle change. - [JsonPropertyName("updatedAt")] - public required DateTimeOffset UpdatedAt { get; set; } -} - -/// Progress snapshot for a shell task, with recent stdout/stderr output and optional process ID. -/// The shell variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskProgressShell : TaskProgress -{ - /// - [JsonIgnore] - public override string Type => "shell"; + public string? Status { get; set; } - /// Process ID when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pid")] - public long? Pid { get; set; } + /// Rendered title. + [JsonPropertyName("title")] + public string? Title { get; set; } - /// Recent stdout/stderr lines from the running shell command. - [JsonPropertyName("recentOutput")] - public required string RecentOutput { get; set; } + /// URL for web-rendered canvases. + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// Progress information for the task, or null when no task with that ID is tracked. +/// Live open-canvas snapshot. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksGetProgressResult +public sealed class CanvasListOpenResult { - /// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. - [JsonPropertyName("progress")] - public TaskProgress? Progress { get; set; } + /// Currently open canvas instances. + [JsonPropertyName("openCanvases")] + public IList OpenCanvases { get => field ??= []; set; } } -/// Identifier of the background task to fetch progress for. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksGetProgressRequest +internal sealed class SessionCanvasListOpenRequest { - /// Task identifier (agent ID or shell ID). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The first sync-waiting task that can currently be promoted to background mode. +/// Canvas open parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksGetCurrentPromotableResult +internal sealed class CanvasOpenRequest { - /// The first sync-waiting task (agent first, then shell) that can currently be promoted to background mode. Omitted if no such task exists. The returned task is guaranteed to have executionMode='sync' and canPromoteToBackground=true at the time of the call. - [JsonPropertyName("task")] - public TaskInfo? Task { get; set; } -} + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; + + /// Owning provider identifier. Optional when the canvasId is unique across providers; required to disambiguate when multiple providers register the same canvasId. + [JsonPropertyName("extensionId")] + public string? ExtensionId { get; set; } + + /// Canvas open input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } + + /// Caller-supplied stable instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksGetCurrentPromotableRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the task was successfully promoted to background mode. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksPromoteToBackgroundResult -{ - /// Whether the task was successfully promoted to background mode. - [JsonPropertyName("promoted")] - public bool Promoted { get; set; } -} - -/// Identifier of the task to promote to background mode. +/// Canvas close parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksPromoteToBackgroundRequest +internal sealed class CanvasCloseRequest { - /// Task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Open canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. +/// Canvas action invocation result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksPromoteCurrentToBackgroundResult +public sealed class CanvasActionInvokeResult { - /// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. Atomic operation: avoids the race window of getCurrentPromotable + promoteToBackground. - [JsonPropertyName("task")] - public TaskInfo? Task { get; set; } + /// Provider-supplied action result. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } } -/// Identifies the target session. +/// Canvas action invocation parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksPromoteCurrentToBackgroundRequest +internal sealed class CanvasActionInvokeRequest { + /// Action name to invoke. + [JsonPropertyName("actionName")] + public string ActionName { get; set; } = string.Empty; + + /// Action input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } + + /// Open canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the background task was successfully cancelled. +/// Internal canvas provider registration parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksCancelResult +internal sealed class CanvasProviderRegisterRequest { - /// Whether the task was successfully cancelled. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } -} + /// Canvas contributions supplied by the provider. + [JsonPropertyName("canvases")] + public IList Canvases { get => field ??= []; set; } -/// Identifier of the background task to cancel. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksCancelRequest -{ - /// Task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Connection identifier for callback routing. + [JsonPropertyName("connectionId")] + public string ConnectionId { get; set; } = string.Empty; + + /// Provider metadata supplied by the host. + [JsonPropertyName("info")] + public JsonElement Info { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the task was removed. False when the task does not exist or is still running/idle. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksRemoveResult -{ - /// Whether the task was removed. Returns false if the task does not exist or is still running/idle (cancel it first). - [JsonPropertyName("removed")] - public bool Removed { get; set; } -} - -/// Identifier of the completed or cancelled task to remove from tracking. +/// Internal canvas provider unregistration parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksRemoveRequest +internal sealed class CanvasProviderUnregisterRequest { - /// Task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Connection identifier to unregister. + [JsonPropertyName("connectionId")] + public string ConnectionId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the message was delivered, with an error message when delivery failed. +/// Machine-readable workflow run failure. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksSendMessageResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowLimitReached), "workflow_limit_reached")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowResumeDeclined), "workflow_resume_declined")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowDurableFailure), "workflow_durable_failure")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowAccountingIncomplete), "workflow_accounting_incomplete")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowProviderDisconnected), "workflow_provider_disconnected")] +public partial class WorkflowRunFailure { - /// Error message if delivery failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Whether the message was successfully delivered or steered. - [JsonPropertyName("sent")] - public bool Sent { get; set; } + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Identifier of the target agent task, message content, and optional sender agent ID. + +/// The workflow_limit_reached variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksSendMessageRequest +public partial class WorkflowRunFailureWorkflowLimitReached : WorkflowRunFailure { - /// Agent ID of the sender, if sent on behalf of another agent. - [JsonPropertyName("fromAgentId")] - public string? FromAgentId { get; set; } + /// + [JsonIgnore] + public override string Type => "workflow_limit_reached"; - /// Agent task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Resource ceiling that stopped the run. + [JsonPropertyName("kind")] + public required WorkflowRunFailureKind Kind { get; set; } - /// Message content to send to the agent. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public required string RunId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Suggested larger ceiling when the runtime can derive one safely. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("suggestedValue")] + public double? SuggestedValue { get; set; } + + /// Approved effective ceiling that was reached. + [JsonPropertyName("value")] + public required double Value { get; set; } } -/// Skill metadata available to a session, with name, description, source, enabled/invocable state, path, plugin, and argument hint. +/// The workflow_resume_declined variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Skill +public partial class WorkflowRunFailureWorkflowResumeDeclined : WorkflowRunFailure { - /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. - [JsonPropertyName("argumentHint")] - public string? ArgumentHint { get; set; } - - /// Canonical slash command name used to invoke the skill, without the leading '/'. - [JsonPropertyName("commandName")] - public string? CommandName { get; set; } - - /// Description of what the skill does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "workflow_resume_declined"; - /// Whether the skill is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Human-readable reason the resume did not proceed. + [JsonPropertyName("reason")] + public required string Reason { get; set; } - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Workflow run identifier whose changed limits were declined. + [JsonPropertyName("runId")] + public required string RunId { get; set; } +} - /// Absolute path to the skill file. - [JsonPropertyName("path")] - public string? Path { get; set; } +/// The workflow_durable_failure variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class WorkflowRunFailureWorkflowDurableFailure : WorkflowRunFailure +{ + /// + [JsonIgnore] + public override string Type => "workflow_durable_failure"; - /// Name of the plugin that provides the skill, when source is 'plugin'. - [JsonPropertyName("pluginName")] - public string? PluginName { get; set; } + /// Stable failure code. + [JsonPropertyName("code")] + public required string Code { get; set; } - /// Source location type (e.g., project, personal-copilot, plugin, builtin). - [JsonPropertyName("source")] - public SkillSource Source { get; set; } + /// Execution-critical durable operation that failed. + [JsonPropertyName("operation")] + public required WorkflowDurableOperation Operation { get; set; } - /// Whether the skill can be invoked by the user as a slash command. - [JsonPropertyName("userInvocable")] - public bool UserInvocable { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public required string RunId { get; set; } } -/// Skills available to the session, with their enabled state. +/// The run stopped because its usage accounting could not be completed. +/// The workflow_accounting_incomplete variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillList +public partial class WorkflowRunFailureWorkflowAccountingIncomplete : WorkflowRunFailure { - /// Available skills. - [JsonPropertyName("skills")] - public IList Skills { get => field ??= []; set; } -} + /// + [JsonIgnore] + public override string Type => "workflow_accounting_incomplete"; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsListRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Confirmed usage in nano-AIU, representing the floor of what the run spent. + [JsonPropertyName("drainedNanoAiu")] + public required long DrainedNanoAiu { get; set; } + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public required string RunId { get; set; } } -/// Skill invocation record with name, path, content, allowed tools, and turn number. +/// The extension that owns the workflow disconnected while the run was executing, so the host halted it. The run's journaled subagent results are preserved so a resume can reuse them. +/// The workflow_provider_disconnected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillsInvokedSkill +public partial class WorkflowRunFailureWorkflowProviderDisconnected : WorkflowRunFailure { - /// Tools that should be auto-approved when this skill is active, captured at invocation time. - [JsonPropertyName("allowedTools")] - public IList? AllowedTools { get; set; } - - /// Full content of the skill file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; - - /// Whether model invocation was disabled when this skill was invoked. - [JsonPropertyName("disableModelInvocation")] - public bool? DisableModelInvocation { get; set; } - - /// Turn number when the skill was invoked. - [JsonPropertyName("invokedAtTurn")] - public long InvokedAtTurn { get; set; } - - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "workflow_provider_disconnected"; - /// Path to the SKILL.md file, or an empty string for an SDK-provided skill without a filesystem identity. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public required string RunId { get; set; } } -/// Skills invoked during this session, ordered by invocation time (most recent last). +/// Durable metadata describing who initiated a workflow pause. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillsGetInvokedResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(WorkflowPauseInfoUser), "user")] +[JsonDerivedType(typeof(WorkflowPauseInfoCheckpoint), "checkpoint")] +public partial class WorkflowPauseInfo { - /// Skills invoked during this session, ordered by invocation time (most recent last). - [JsonPropertyName("skills")] - public IList Skills { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Identifies the target session. + +/// The user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsGetInvokedRequest +public partial class WorkflowPauseInfoUser : WorkflowPauseInfo { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "user"; } -/// Name of the skill to enable for the session. +/// The checkpoint variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsEnableRequest +public partial class WorkflowPauseInfoCheckpoint : WorkflowPauseInfo { - /// Name of the skill to enable. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "checkpoint"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Stable author-defined checkpoint key that initiated the pause. + [JsonPropertyName("key")] + public required string Key { get; set; } } -/// Name of the skill to disable for the session. +/// Complete current or terminal workflow run envelope. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsDisableRequest +public sealed class WorkflowRunResult { - /// Name of the skill to disable. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// One-based execution attempt represented by this envelope. Absent before the first attempt starts or when returned by an older runtime. + [JsonPropertyName("attempt")] + public long? Attempt { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Error message for an errored run. + [JsonPropertyName("error")] + public string? Error { get; set; } -/// Diagnostics from reloading skill definitions, with warnings and errors as separate lists. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillsLoadDiagnostics -{ - /// Errors emitted while loading skills (e.g. skills that failed to load entirely). - [JsonPropertyName("errors")] - public IList Errors { get => field ??= []; set; } + /// Machine-readable failure details for a halted or errored run. + [JsonPropertyName("failure")] + public WorkflowRunFailure? Failure { get; set; } - /// Warnings emitted while loading skills (e.g. skills that loaded but had issues). - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } -} + /// Structured pause initiator metadata for a paused attempt. + [JsonPropertyName("pauseInfo")] + public WorkflowPauseInfo? PauseInfo { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsReloadRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Reason for a halted or cancelled run. + [JsonPropertyName("reason")] + public string? Reason { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsEnsureLoadedRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Completed workflow result. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } -/// Recorded MCP server connection failure. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerFailureInfo -{ - /// Failure message produced when the MCP server connection failed. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// epoch-ms timestamp at which the failure was recorded. - [JsonPropertyName("timestamp")] - public long Timestamp { get; set; } -} + /// Partial journal and progress snapshot for a halted, cancelled, or errored run. + [JsonPropertyName("snapshot")] + public JsonElement? Snapshot { get; set; } -/// Recorded MCP server pending-auth state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerNeedsAuthInfo -{ - /// epoch-ms timestamp at which the server signalled it needs authentication. - [JsonPropertyName("timestamp")] - public long Timestamp { get; set; } + /// Current or terminal workflow run status. + [JsonPropertyName("status")] + public WorkflowRunStatus Status { get; set; } } -/// Host-level state, omitted when no MCP host is initialized. +/// Wire-only per-invocation workflow resource ceiling overrides. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpHostState +public sealed class WorkflowRunLimits { - /// Names of currently-connected MCP clients. - [JsonPropertyName("clients")] - public IList Clients { get => field ??= []; set; } - - /// Configured servers that are explicitly disabled. - [JsonPropertyName("disabledServers")] - public IList DisabledServers { get => field ??= []; set; } - - /// Map of server name to recorded connection failure. - [JsonPropertyName("failedServers")] - public IDictionary FailedServers { get => field ??= new Dictionary(); set; } - - /// Configured servers filtered out by MCP server policy. - [JsonPropertyName("filteredServers")] - public IList FilteredServers { get => field ??= []; set; } - - /// Whether third-party MCP servers are policy-enabled for this session. - [JsonPropertyName("mcp3pEnabled")] - public bool Mcp3pEnabled { get; set; } + /// Maximum AI credits consumed by workflow subagents and their descendants. The post-paid ceiling is soft: parallel turns can settle beyond it before the run stops. + [JsonPropertyName("maxAiCredits")] + public double? MaxAiCredits { get; set; } - /// Map of server name to recorded pending-auth state. - [JsonPropertyName("needsAuthServers")] - public IDictionary NeedsAuthServers { get => field ??= new Dictionary(); set; } + /// Maximum number of workflow subagents that may run concurrently. + [JsonPropertyName("maxConcurrentSubagents")] + public long? MaxConcurrentSubagents { get; set; } - /// Names of servers with in-flight connection attempts. - [JsonPropertyName("pendingConnections")] - public IList PendingConnections { get => field ??= []; set; } -} + /// Maximum total number of workflow subagents that may be admitted. + [JsonPropertyName("maxTotalSubagents")] + public long? MaxTotalSubagents { get; set; } -/// Owned installation that a listed MCP server's live configuration came from. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerOwnership -{ - /// Stable installation identifier from the owned installation receipt. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// Maximum accumulated active-execution time in seconds. Active execution includes the entire extension body, subprocess waits, queued-agent waits, and sleeps; time between resumed attempts is not counted. + [JsonPropertyName("timeoutSeconds")] + public double? TimeoutSeconds { get; set; } } -/// MCP server status entry, including config source/plugin source and any connection error. +/// Options controlling workflow invocation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServer +public sealed class WorkflowRunOptions { - /// Human-readable display name supplied by a managed server catalog. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } - - /// Error message if the server failed to connect. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Server name (config key). - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("name")] - public string Name { get; set; } = string.Empty; - - /// Owned installation this entry's live configuration came from. Absent for manual, workspace, plugin, builtin and same-name servers, and on runtimes without owned installations. - [JsonPropertyName("owned")] - public McpServerOwnership? Owned { get; set; } - - /// Server-advertised metadata for a connected server. Omitted when no live connection metadata is available, including while pending or when failed, disabled, stopped, or not configured. - [JsonPropertyName("serverMetadata")] - public McpServerMetadata? ServerMetadata { get; set; } - - /// Configuration source: user, workspace, plugin, builtin, or managed. - [JsonPropertyName("source")] - public McpServerSource? Source { get; set; } + /// Per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Plugin name that provided this server, when source is plugin. - [JsonPropertyName("sourcePlugin")] - public string? SourcePlugin { get; set; } + /// Whether to emit workflow phase names to the session transcript. + [JsonPropertyName("logPhaseNames")] + public bool? LogPhaseNames { get; set; } - /// Plugin version that provided this server, when source is plugin. - [JsonPropertyName("sourcePluginVersion")] - public string? SourcePluginVersion { get; set; } + /// Whether to notify the originating session when the workflow completes. + [JsonPropertyName("notifyOnComplete")] + public bool? NotifyOnComplete { get; set; } - /// Connection status: connected, failed, needs-auth, pending, disabled, stopped, or not_configured. - [JsonPropertyName("status")] - public McpServerStatus Status { get; set; } + /// Run identifier whose journal and progress should seed this resumed run. + [JsonPropertyName("resumeFromRunId")] + public string? ResumeFromRunId { get; set; } } -/// MCP servers configured for the session, with their connection status and host-level state. +/// Parameters for invoking a registered workflow. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerList +internal sealed class WorkflowRunRequest { - /// Host-level state, omitted when no MCP host is initialized. - [JsonPropertyName("host")] - public McpHostState? Host { get; set; } + /// Workflow input value. + [JsonPropertyName("args")] + public JsonElement Args { get; set; } - /// Configured MCP servers. - [JsonPropertyName("servers")] - public IList Servers { get => field ??= []; set; } -} + /// Registered workflow name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Workflow invocation options. + [JsonPropertyName("options")] + public WorkflowRunOptions? Options { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpListRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Normalized MCP Apps discovery metadata from a tool's `_meta.ui` block. +/// Resolved persisted workflow identity and resumed run envelope. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpToolUi +public sealed class WorkflowResumeResult { - /// URI of the tool's MCP App resource, typically a `ui://` resource identifier. Use `session.mcp.resources.read` to fetch its HTML and resource metadata. - [JsonPropertyName("resourceUri")] - public string? ResourceUri { get; set; } + /// Terminal resumed run envelope. + [JsonPropertyName("run")] + public WorkflowRunResult Run { get => field ??= new(); set; } - /// Tool visibility advertised by the server. When absent, MCP Apps defaults apply. - [JsonPropertyName("visibility")] - public IList? Visibility { get; set; } + /// Persisted workflow name resolved for the resumed run. + [JsonPropertyName("workflowName")] + public string WorkflowName { get; set; } = string.Empty; } -/// MCP tool metadata with tool name, optional description, and normalized MCP Apps discovery metadata. +/// Parameters for resuming a workflow run from its persisted identity. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpTools +internal sealed class WorkflowResumeRequest { - /// Tool description, when provided. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Tool name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Optional per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Normalized MCP Apps discovery metadata. An empty object indicates that a valid `_meta.ui` block was present without recognized fields. - [JsonPropertyName("ui")] - public McpToolUi? Ui { get; set; } -} + /// Whether to emit workflow phase names to the session transcript. + [JsonPropertyName("logPhaseNames")] + public bool? LogPhaseNames { get; set; } -/// Tools exposed by the connected MCP server. Throws when the server is not connected. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpListToolsResult -{ - /// Tools exposed by the server. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } -} + /// Whether to notify the originating session when the workflow completes. + [JsonPropertyName("notifyOnComplete")] + public bool? NotifyOnComplete { get; set; } -/// Server name whose tool list should be returned. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpListToolsRequest -{ - /// Name of the connected MCP server whose tools to list. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Name of the MCP server to enable for the session. +/// Options for an internal tool-originated workflow invocation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpEnableRequest +internal sealed class WorkflowToolRunOptions { - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Name of the MCP server to enable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public required string ServerName { get; set; } + /// Run identifier whose journal and progress should seed this resumed run. + [JsonPropertyName("resumeFromRunId")] + public string? ResumeFromRunId { get; set; } } -/// Name of the MCP server to enable for the session. +/// Internal parameters for invoking a registered workflow from a tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpEnableRequestWithSession +internal sealed class WorkflowToolRunRequest { - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Workflow input value. + [JsonPropertyName("args")] + public JsonElement Args { get; set; } - /// Name of the MCP server to enable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Registered workflow name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Tool-originated workflow invocation options. + [JsonPropertyName("options")] + public WorkflowToolRunOptions? Options { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} - -/// Name of the MCP server to disable for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDisableRequest -{ - /// Required for an owned installation; omission preserves only manual-server behaviour. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } - /// Name of the MCP server to disable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public required string ServerName { get; set; } + /// Opaque identifier of the originating tool call. + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } -/// Name of the MCP server to disable for the session. +/// Internal parameters for resuming a workflow run from a tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpDisableRequestWithSession +internal sealed class WorkflowToolResumeRequest { - /// Required for an owned installation; omission preserves only manual-server behaviour. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Optional per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Name of the MCP server to disable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Opaque identifier of the originating tool call. + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } -/// Identifies the target session. +/// Parameters for retrieving a workflow run. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpReloadRequest +internal sealed class WorkflowGetRunRequest { + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of moving in-flight MCP loading to the background. +/// Declared or approved workflow resource ceilings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MoveMcpLoadingToBackgroundResult +public sealed class WorkflowDeclaredLimits { - /// Whether an in-flight MCP load was moved to the background, releasing turns that were waiting on it. False when no MCP load was in flight or the waiting turns had already been released. - [JsonPropertyName("movedToBackground")] - public bool MovedToBackground { get; set; } + /// Maximum AI credits consumed by subagents and descendants. + [JsonPropertyName("maxAiCredits")] + public double? MaxAiCredits { get; set; } + + /// Maximum concurrently active subagents. + [JsonPropertyName("maxConcurrentSubagents")] + public long? MaxConcurrentSubagents { get; set; } + + /// Maximum total subagents spawned by the run. + [JsonPropertyName("maxTotalSubagents")] + public long? MaxTotalSubagents { get; set; } + + /// Maximum accumulated active execution time in seconds. + [JsonPropertyName("timeoutSeconds")] + public double? TimeoutSeconds { get; set; } } -/// Identifies the target session. +/// Durable workflow resource consumption. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpMoveLoadingToBackgroundRequest +public sealed class WorkflowRunConsumed { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Accumulated active execution time in milliseconds. + [JsonPropertyName("activeMs")] + public long ActiveMs { get; set; } + + /// AI usage consumed by the run in nano-AIU. + [JsonPropertyName("nanoAiu")] + public long NanoAiu { get; set; } + + /// Total subagents spawned by the run. + [JsonPropertyName("subagents")] + public long Subagents { get; set; } } -/// MCP server allowed by policy, with server name and optional PII-free explanatory note. +/// Current workflow phase identity. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAllowedServer +public sealed class WorkflowCurrentPhase { - /// Allowed server name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Current phase identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// PII-free note explaining why the server was allowed. - [JsonPropertyName("redactedNote")] - public string? RedactedNote { get; set; } + /// Zero-based declared phase ordinal, or null for an undeclared phase. + [JsonPropertyName("ordinal")] + public long? Ordinal { get; set; } } -/// MCP server whose connection attempt failed. +/// Prompt-safe terminal workflow outcome. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpFailedServer +public sealed class WorkflowRunTerminal { - /// The captured connection failure detail. + /// Human-readable terminal error. [JsonPropertyName("error")] public string? Error { get; set; } - /// The config key of the server that failed to connect. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; -} - -/// MCP server filtered by policy, with name, reason, and optional redacted reason. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpFilteredServer -{ - /// Deprecated. This field is no longer populated. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("enterpriseName")] - public string? EnterpriseName { get; set; } + /// Machine-readable terminal failure. + [JsonPropertyName("failure")] + public WorkflowRunFailure? Failure { get; set; } - /// Filtered server name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Pause initiator metadata, or null when the run did not pause. + [JsonPropertyName("pauseInfo")] + public WorkflowPauseInfo? PauseInfo { get; set; } - /// Human-readable filter reason. + /// Human-readable terminal reason. [JsonPropertyName("reason")] - public string Reason { get; set; } = string.Empty; + public string? Reason { get; set; } - /// PII-free filter reason. - [JsonPropertyName("redactedReason")] - public string? RedactedReason { get; set; } + /// Prompt-safe preview of the completed result. + [JsonPropertyName("resultPreview")] + public string? ResultPreview { get; set; } } -/// MCP server startup filtering result. +/// Durable workflow run summary with read-time live overlays. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpStartServersResult +public sealed class WorkflowRunSummary { - /// Non-default servers allowed by policy. - [JsonPropertyName("allowedServers")] - public IList? AllowedServers { get; set; } + /// Epoch milliseconds when the current active segment started, or null while inactive. + [JsonPropertyName("activeSegmentStartedAt")] + public long? ActiveSegmentStartedAt { get; set; } - /// Servers whose connection attempt failed. - [JsonPropertyName("failedServers")] - public IList? FailedServers { get; set; } + /// Approved effective resource ceilings, or null until approved. + [JsonPropertyName("approved")] + public WorkflowDeclaredLimits? Approved { get; set; } - /// Servers filtered out before startup. - [JsonPropertyName("filteredServers")] - public IList FilteredServers { get => field ??= []; set; } -} + /// Whether the durable run state currently passes runtime resume eligibility checks. + [JsonPropertyName("canResume")] + public bool CanResume { get; set; } -/// Opaque MCP reload configuration. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpReloadWithConfigRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Epoch milliseconds when the run completed, or null while nonterminal. + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } -/// 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(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpExecuteSamplingResult -{ -} + /// Durable resource consumption. + [JsonPropertyName("consumed")] + public WorkflowRunConsumed Consumed { get => field ??= new(); set; } -/// Outcome of an MCP sampling execution: success result, failure error, or cancellation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSamplingExecutionResult -{ - /// 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. - [JsonPropertyName("action")] - public McpSamplingExecutionAction Action { get; set; } + /// Epoch milliseconds when the run was created. + [JsonPropertyName("createdAt")] + public long CreatedAt { get; set; } - /// Error description, present when action='failure'. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Current phase identity, or null before any phase is entered. + [JsonPropertyName("currentPhase")] + public WorkflowCurrentPhase? CurrentPhase { get; set; } - /// 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. - [JsonPropertyName("result")] - public McpExecuteSamplingResult? Result { get; set; } -} + /// Resource ceilings declared by the workflow. + [JsonPropertyName("declaredLimits")] + public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } -/// 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(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpExecuteSamplingRequest -{ -} + /// Number of phases declared by the workflow. + [JsonPropertyName("declaredPhaseCount")] + public long DeclaredPhaseCount { get; set; } -/// Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpExecuteSamplingParams -{ - /// 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). - [JsonPropertyName("mcpRequestId")] - public JsonElement McpRequestId { get; set; } + /// Human-readable workflow description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// 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. - [JsonPropertyName("request")] - public McpExecuteSamplingRequest Request { get => field ??= new(); set; } + /// Number of direct workflow agents currently live. + [JsonPropertyName("liveAgentCount")] + public long LiveAgentCount { get; set; } - /// 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. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Epoch milliseconds when this live-overlay snapshot was observed. + [JsonPropertyName("observedAt")] + public long ObservedAt { get; set; } - /// Name of the MCP server that initiated the sampling request. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Monotonic durable run revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; -/// Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpCancelSamplingExecutionResult -{ - /// 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). - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } -} + /// Epoch milliseconds when execution first started, or null before start. + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } -/// The requestId previously passed to executeSampling that should be cancelled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpCancelSamplingExecutionParams -{ - /// The requestId previously passed to executeSampling that should be cancelled. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Current workflow run status. + [JsonPropertyName("status")] + public WorkflowRunStatus Status { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Terminal run outcome, or null while nonterminal. + [JsonPropertyName("terminal")] + public WorkflowRunTerminal? Terminal { get; set; } -/// Env-value mode recorded on the session after the update. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSetEnvValueModeResult -{ - /// Mode recorded on the session after the update. - [JsonPropertyName("mode")] - public McpSetEnvValueModeDetails Mode { get; set; } -} + /// Total direct workflow agents spawned across all attempts. + [JsonPropertyName("totalSpawnedAgentCount")] + public long TotalSpawnedAgentCount { get; set; } -/// Mode controlling how MCP server env values are resolved (`direct` or `indirect`). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpSetEnvValueModeParams -{ - /// 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". - [JsonPropertyName("mode")] - public McpSetEnvValueModeDetails Mode { get; set; } + /// Epoch milliseconds when the durable run was last updated. + [JsonPropertyName("updatedAt")] + public long UpdatedAt { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Registered workflow name. + [JsonPropertyName("workflowName")] + public string WorkflowName { get; set; } = string.Empty; } -/// Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). +/// A page of workflow runs in durable creation order. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpRemoveGitHubResult +public sealed class WorkflowListRunsResult { - /// 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). - [JsonPropertyName("removed")] - public bool Removed { get; set; } -} + /// Whether terminal runs newer than this page exist. + [JsonPropertyName("hasMoreNewer")] + public bool? HasMoreNewer { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpRemoveGitHubRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Newest terminal-run cursor in this page, or null when the terminal window is empty. + [JsonPropertyName("newestSeq")] + public long? NewestSeq { get; set; } -/// Result of configuring GitHub MCP. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigureGitHubResult -{ - /// Whether GitHub MCP configuration changed. - [JsonPropertyName("changed")] - public bool Changed { get; set; } + /// Oldest terminal-run cursor in this page, or null when the terminal window is empty. + [JsonPropertyName("oldestSeq")] + public long? OldestSeq { get; set; } + + /// Number of terminal runs older than this page. + [JsonPropertyName("omittedOlder")] + public long? OmittedOlder { get; set; } + + /// Workflow run summaries in durable creation order. + [JsonPropertyName("runs")] + public IList Runs { get => field ??= []; set; } } -/// Credential-free authentication identity used to configure GitHub MCP. +/// Parameters for paging workflow runs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigureGitHubRequest +internal sealed class WorkflowListRunsRequest { + /// Exclusive forward cursor. + [JsonPropertyName("afterSeq")] + public long? AfterSeq { get; set; } + + /// Exclusive backward cursor. + [JsonPropertyName("beforeSeq")] + public long? BeforeSeq { get; set; } + + /// Maximum terminal runs to return. Defaults to 200 and is capped at 500. + [JsonPropertyName("limit")] + public int? Limit { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. +/// Prompt-safe durable identity and live status for a direct workflow agent. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpStartServerRequest +public sealed class WorkflowAgentSummary { - /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// Accumulated active agent time in milliseconds. + [JsonPropertyName("activeMs")] + public long ActiveMs { get; set; } - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Prompt-safe live activity text. + [JsonPropertyName("activity")] + public string? Activity { get; set; } - /// Name of the MCP server to start. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } -} + /// Stable direct-agent identifier. + [JsonPropertyName("agentId")] + public string AgentId { get; set; } = string.Empty; -/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpStartServerRequestWithSession -{ - /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// Registered agent type. + [JsonPropertyName("agentType")] + public string AgentType { get; set; } = string.Empty; - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Epoch milliseconds when the agent completed. + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } - /// Name of the MCP server to start. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Friendly, non-unique name intended for display. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Friendly, non-unique name intended for display. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; -/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpRestartServerRequest -{ - /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// Phase identifier active when the agent was launched, or null. + [JsonPropertyName("phaseId")] + public string? PhaseId { get; set; } - /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Model requested when the agent was launched. + [JsonPropertyName("requestedModel")] + public string? RequestedModel { get; set; } - /// Name of the MCP server to restart. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } -} + /// Concrete model resolved for the agent. + [JsonPropertyName("resolvedModel")] + public string? ResolvedModel { get; set; } -/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRestartServerRequestWithSession -{ - /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// Owning workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Epoch milliseconds when the agent started. + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } - /// Name of the MCP server to restart. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Current durable or live agent status. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Tool-call identifier that launched the agent. + [JsonPropertyName("toolCallId")] + public string ToolCallId { get; set; } = string.Empty; } -/// Server name for an individual MCP server stop. +/// Durable lifecycle and timing for one workflow phase. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpStopServerRequest +public sealed class WorkflowPhaseObservation { - /// Exact owned receipt identity. Stop also forgets this session's durable activation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Completed active time accumulated by this phase in milliseconds. + [JsonPropertyName("accumulatedActiveMs")] + public long AccumulatedActiveMs { get; set; } - /// Name of the MCP server to stop. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } -} + /// Epoch milliseconds when this phase completed; for a skipped phase, the synthetic skip timestamp (equal to `startedAt`). + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } -/// Server name for an individual MCP server stop. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpStopServerRequestWithSession -{ - /// Exact owned receipt identity. Stop also forgets this session's durable activation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Current live active time for this phase in milliseconds. + [JsonPropertyName("currentActiveMs")] + public long CurrentActiveMs { get; set; } - /// Name of the MCP server to stop. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Optional human-readable phase detail. + [JsonPropertyName("detail")] + public string? Detail { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Number of times execution entered this phase. + [JsonPropertyName("entryCount")] + public long EntryCount { get; set; } -/// Registration parameters for an external MCP client. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRegisterExternalClientRequest -{ - /// Logical server name for the external client. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Phase identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Most recent run attempt that entered this phase, or `0` if the phase has never been entered. + [JsonPropertyName("lastEnteredRunAttempt")] + public long LastEnteredRunAttempt { get; set; } -/// Server name identifying the external client to remove. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpUnregisterExternalClientRequest -{ - /// Server name of the external client to unregister. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Direct agents in this phase that are currently live. + [JsonPropertyName("liveAgentCount")] + public long LiveAgentCount { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Zero-based declared phase ordinal, or null for an undeclared phase. + [JsonPropertyName("ordinal")] + public long? Ordinal { get; set; } -/// Whether the named MCP server is running. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpIsServerRunningResult -{ - /// True if the server has an active client and transport. - [JsonPropertyName("running")] - public bool Running { get; set; } -} + /// Epoch milliseconds when this phase first started; for a skipped phase, the synthetic skip timestamp (equal to `completedAt`). + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } -/// Server name to check running status for. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpIsServerRunningRequest -{ - /// Name of the MCP server to check. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Derived lifecycle state of the phase. + [JsonPropertyName("status")] + public WorkflowPhaseStatus Status { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Human-readable phase title. + [JsonPropertyName("title")] + public string Title { get; set; } = string.Empty; -/// Indicates whether the pending MCP OAuth response was accepted. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthHandlePendingResult -{ - /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Total direct agents associated with this phase. + [JsonPropertyName("totalAgentCount")] + public long TotalAgentCount { get; set; } } -/// Host response to the pending OAuth request. -/// Polymorphic base type discriminated by kind. +/// One durable workflow progress record. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpOauthPendingRequestResponseToken), "token")] -[JsonDerivedType(typeof(McpOauthPendingRequestResponseCancelled), "cancelled")] -public partial class McpOauthPendingRequestResponse +public sealed class WorkflowProgressLine { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Resume attempt that emitted this record. + [JsonPropertyName("attempt")] + public long Attempt { get; set; } + /// Progress record kind. + [JsonPropertyName("kind")] + public WorkflowLogLineKind Kind { get; set; } -/// The token variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthPendingRequestResponseToken : McpOauthPendingRequestResponse -{ - /// - [JsonIgnore] - public override string Kind => "token"; + /// Phase active when the record was emitted, or null before any phase. + [JsonPropertyName("phaseId")] + public string? PhaseId { get; set; } - /// Access token acquired by the SDK host. - [JsonPropertyName("accessToken")] - public required string AccessToken { get; set; } + /// Epoch milliseconds when the record was persisted. + [JsonPropertyName("recordedAt")] + public long RecordedAt { get; set; } - /// Token lifetime in seconds, if known. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("expiresIn")] - public long? ExpiresIn { get; set; } + /// Global monotonic sequence number within the run. + [JsonPropertyName("seq")] + public long Seq { get; set; } - /// OAuth token type. Defaults to bearer when omitted. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("tokenType")] - public string? TokenType { get; set; } + /// Prompt-safe progress text. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; } -/// The cancelled variant of . +/// A bidirectional page of workflow progress. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthPendingRequestResponseCancelled : McpOauthPendingRequestResponse -{ - /// - [JsonIgnore] - public override string Kind => "cancelled"; -} - -/// Pending MCP OAuth request ID and host-provided token or cancellation response. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthHandlePendingRequest +public sealed class WorkflowProgressPage { - /// OAuth request identifier from the mcp.oauth_required event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Whether progress records newer than this page exist. + [JsonPropertyName("hasMoreNewer")] + public bool HasMoreNewer { get; set; } - /// Host response to the pending OAuth request. - [JsonPropertyName("result")] - public McpOauthPendingRequestResponse Result { get => field ??= new(); set; } + /// Whether progress records older than this page exist. + [JsonPropertyName("hasMoreOlder")] + public bool HasMoreOlder { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Newest sequence number in this page, or null when empty. + [JsonPropertyName("newestSeq")] + public long? NewestSeq { get; set; } -/// Identifies the MCP server whose persisted OAuth credentials were updated. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthAuthenticationStateChangedRequest -{ - /// Whether the target session must mint a session-scoped access token instead of reusing a shared access token persisted by another session. - [JsonPropertyName("refreshSessionToken")] - public bool? RefreshSessionToken { get; set; } + /// Oldest sequence number in this page, or null when empty. + [JsonPropertyName("oldestSeq")] + public long? OldestSeq { get; set; } - /// Name of the MCP server whose OAuth credentials were updated. Omit only when the host cannot identify the server. - [JsonPropertyName("serverName")] - public string? ServerName { get; set; } + /// Progress records in sequence order. + [JsonPropertyName("records")] + public IList Records { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Run revision reflected by this page. + [JsonPropertyName("revision")] + public long Revision { get; set; } } -/// An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. +/// Full workflow run observability detail. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionMcpOauthPrepareLoginResult +public sealed class WorkflowRunDetail { - /// Original expiry, not extended by consumption, retries or cancellation. - [JsonPropertyName("expiresAt")] - public DateTimeOffset ExpiresAt { get; set; } + /// Epoch milliseconds when the current active segment started, or null while inactive. + [JsonPropertyName("activeSegmentStartedAt")] + public long? ActiveSegmentStartedAt { get; set; } - /// Retain with the original requester and use for one login or cancellation. - [JsonPropertyName("loginId")] - public string LoginId { get; set; } = string.Empty; -} + /// Durable identities and live statuses for direct workflow agents. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } -/// Effect-free preparation bound to the existing local session, requester and installation, with frozen options. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpOauthPrepareLoginRequest -{ - /// Text shown on the loopback callback page after successful authorisation. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(2048)] - [JsonPropertyName("callbackSuccessMessage")] - public string? CallbackSuccessMessage { get; set; } + /// Approved effective resource ceilings, or null until approved. + [JsonPropertyName("approved")] + public WorkflowDeclaredLimits? Approved { get; set; } - /// Display name used by the incumbent OAuth client-registration flow. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(2048)] - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Whether the durable run state currently passes runtime resume eligibility checks. + [JsonPropertyName("canResume")] + public bool CanResume { get; set; } - /// Exact installation identity from owned inventory, never a server-name alias. - [JsonPropertyName("expectedInstallationId")] - public string ExpectedInstallationId { get; set; } = string.Empty; + /// Epoch milliseconds when the run completed, or null while nonterminal. + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } - /// Request a new authorisation rather than accepting a usable cached grant. - [JsonPropertyName("forceReauth")] - public bool? ForceReauth { get; set; } + /// Durable resource consumption. + [JsonPropertyName("consumed")] + public WorkflowRunConsumed Consumed { get => field ??= new(); set; } - /// Name recorded by the authoritative owned installation receipt. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Epoch milliseconds when the run was created. + [JsonPropertyName("createdAt")] + public long CreatedAt { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Current phase identity, or null before any phase is entered. + [JsonPropertyName("currentPhase")] + public WorkflowCurrentPhase? CurrentPhase { get; set; } -/// OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthLoginResult -{ - /// Opaque authorization identifier returned only for a host-managed redirect URI. The runtime also sends it as the OAuth state value, so the callback endpoint can read state and pass it with the full callback URL to session.mcp.oauth.complete. - [JsonPropertyName("authorizationId")] - public string? AuthorizationId { get; set; } + /// Resource ceilings declared by the workflow. + [JsonPropertyName("declaredLimits")] + public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } - /// 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. For the default loopback flow, the runtime starts its listener before returning. With redirectUri, the host receives the callback and completes it through session.mcp.oauth.complete. The runtime continues the flow in the background and signals completion via session.mcp_server_status_changed. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("authorizationUrl")] - public string? AuthorizationUrl { get; set; } + /// Number of phases declared by the workflow. + [JsonPropertyName("declaredPhaseCount")] + public long DeclaredPhaseCount { get; set; } - /// Runtime-issued owned flow identity; never a server name or installation operation ID. - [JsonPropertyName("loginId")] - public string? LoginId { get; set; } + /// Human-readable workflow description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Explicit outcome for owned sign-in. Manual callers retain their legacy response shape. - [JsonPropertyName("status")] - public McpOwnedOauthLoginStatus? Status { get; set; } -} + /// Number of direct workflow agents currently live. + [JsonPropertyName("liveAgentCount")] + public long LiveAgentCount { get; set; } -/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthLoginRequest -{ - /// 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. - [JsonPropertyName("callbackSuccessMessage")] - public string? CallbackSuccessMessage { get; set; } + /// Epoch milliseconds when this live-overlay snapshot was observed. + [JsonPropertyName("observedAt")] + public long ObservedAt { get; set; } - /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. - [JsonPropertyName("clientId")] - public string? ClientId { get; set; } + /// Lifecycle and timing observations for each workflow phase. + [JsonPropertyName("phases")] + public IList Phases { get => field ??= []; set; } - /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Bidirectional page of durable workflow progress. + [JsonPropertyName("progress")] + public WorkflowProgressPage Progress { get => field ??= new(); set; } - /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. - [JsonPropertyName("clientSecret")] - public string? ClientSecret { get; set; } + /// Monotonic durable run revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } - /// Exact owned receipt identity. Owned login never uses an implicit helper session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. - [JsonPropertyName("forceReauth")] - public bool? ForceReauth { get; set; } + /// Epoch milliseconds when execution first started, or null before start. + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } - /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. - [JsonPropertyName("grantType")] - public McpOauthLoginGrantType? GrantType { get; set; } + /// Current workflow run status. + [JsonPropertyName("status")] + public WorkflowRunStatus Status { get; set; } - /// - /// Required for owned login. Consumes the exact prepareLogin handle once. - /// Set forceReauth and display options during preparation, not consumption. - /// - [JsonPropertyName("loginId")] - public string? LoginId { get; set; } + /// Terminal run outcome, or null while nonterminal. + [JsonPropertyName("terminal")] + public WorkflowRunTerminal? Terminal { get; set; } - /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. - [JsonPropertyName("publicClient")] - public bool? PublicClient { get; set; } + /// Total direct workflow agents spawned across all attempts. + [JsonPropertyName("totalSpawnedAgentCount")] + public long TotalSpawnedAgentCount { get; set; } - /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("redirectUri")] - public string? RedirectUri { get; set; } + /// Epoch milliseconds when the durable run was last updated. + [JsonPropertyName("updatedAt")] + public long UpdatedAt { get; set; } - /// Name of the remote MCP server to authenticate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public required string ServerName { get; set; } + /// Registered workflow name. + [JsonPropertyName("workflowName")] + public string WorkflowName { get; set; } = string.Empty; } -/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. +/// Parameters for paging workflow progress. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthLoginRequestWithSession +internal sealed class WorkflowGetRunProgressRequest { - /// 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. - [JsonPropertyName("callbackSuccessMessage")] - public string? CallbackSuccessMessage { get; set; } - - /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. - [JsonPropertyName("clientId")] - public string? ClientId { get; set; } - - /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } - - /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. - [JsonPropertyName("clientSecret")] - public string? ClientSecret { get; set; } - - /// Exact owned receipt identity. Owned login never uses an implicit helper session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } - - /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. - [JsonPropertyName("forceReauth")] - public bool? ForceReauth { get; set; } - - /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. - [JsonPropertyName("grantType")] - public McpOauthLoginGrantType? GrantType { get; set; } + /// Exclusive forward cursor. + [JsonPropertyName("afterSeq")] + public long? AfterSeq { get; set; } - /// - /// Required for owned login. Consumes the exact prepareLogin handle once. - /// Set forceReauth and display options during preparation, not consumption. - /// - [JsonPropertyName("loginId")] - public string? LoginId { get; set; } + /// Exclusive backward cursor. + [JsonPropertyName("beforeSeq")] + public long? BeforeSeq { get; set; } - /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. - [JsonPropertyName("publicClient")] - public bool? PublicClient { get; set; } + /// Maximum records to return. Defaults to 200 and is capped at 500. + [JsonPropertyName("limit")] + public int? Limit { get; set; } - /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("redirectUri")] - public string? RedirectUri { get; set; } + /// Optional phase identifier used to scope records and cursors. + [JsonPropertyName("phaseId")] + public string? PhaseId { get; set; } - /// Name of the remote MCP server to authenticate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Host-delivered callback for a runtime-managed MCP OAuth login. +/// Parameters for cancelling a workflow run. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthCompleteRequest +internal sealed class WorkflowCancelRequest { - /// Opaque identifier returned by session.mcp.oauth.login for the pending external callback. - [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("authorizationId")] - public string AuthorizationId { get; set; } = string.Empty; - - /// Full externally visible HTTPS callback URL received by the host, including the authorization response query parameters. Applications behind a reverse proxy must reconstruct the public URL rather than passing an internal proxy URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("callbackUrl")] - public string CallbackUrl { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Passive MCP OAuth probe result. `authenticated` means the server accepted the probe request while an OAuth-origin access token was attached; it does not prove the server required or independently validated that token. The probe does not make a second unauthenticated request. Failed is an expected probe-domain outcome; JSON-RPC errors are reserved for API-call failures. -/// Polymorphic base type discriminated by status. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "status", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpOauthProbeResultNoAuthRequired), "no-auth-required")] -[JsonDerivedType(typeof(McpOauthProbeResultAuthenticated), "authenticated")] -[JsonDerivedType(typeof(McpOauthProbeResultNeedsAuth), "needs-auth")] -[JsonDerivedType(typeof(McpOauthProbeResultFailed), "failed")] -public partial class McpOauthProbeResult -{ - /// The type discriminator. - [JsonPropertyName("status")] - public virtual string Status { get; set; } = string.Empty; -} - - -/// The no-auth-required variant of . +/// Parameters for pausing a running workflow. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultNoAuthRequired : McpOauthProbeResult +internal sealed class WorkflowPauseRequest { - /// - [JsonIgnore] - public override string Status => "no-auth-required"; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// HTTP response returned by the server. - [JsonPropertyName("httpResponse")] - public required McpOauthHttpResponse HttpResponse { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The authenticated variant of . +/// RPC data type for SessionWorkflowPauseAtCheckpoint operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultAuthenticated : McpOauthProbeResult +internal sealed class SessionWorkflowPauseAtCheckpointResult { - /// - [JsonIgnore] - public override string Status => "authenticated"; - - /// HTTP response returned by the server. - [JsonPropertyName("httpResponse")] - public required McpOauthHttpResponse HttpResponse { get; set; } + /// Whether this execution attempt must pause or may continue. + [JsonPropertyName("action")] + public WorkflowPauseCheckpointAction Action { get; set; } } -/// The needs-auth variant of . +/// Parameters for an owned durable pause checkpoint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultNeedsAuth : McpOauthProbeResult +internal sealed class WorkflowPauseCheckpointRequest { - /// - [JsonIgnore] - public override string Status => "needs-auth"; + /// Opaque token identifying the execution attempt that reached the checkpoint. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// HTTP 401 or 403 response returned by the server. - [JsonPropertyName("httpResponse")] - public required McpOauthHttpResponse HttpResponse { get; set; } + /// Stable author-defined checkpoint key. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Why authentication is needed. - [JsonPropertyName("reason")] - public required McpOauthProbeNeedsAuthReason Reason { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// Parsed WWW-Authenticate challenge parameters, when present and parseable. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("wwwAuthenticateParams")] - public McpOauthWWWAuthenticateParams? WwwAuthenticateParams { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The failed variant of . +/// Acknowledgement that a workflow request was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultFailed : McpOauthProbeResult +public sealed class WorkflowAckResult { - /// - [JsonIgnore] - public override string Status => "failed"; - - /// Human-readable probe failure detail. - [JsonPropertyName("error")] - public required string Error { get; set; } - - /// HTTP response returned by the server, when the probe reached the server and captured the complete response. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("httpResponse")] - public McpOauthHttpResponse? HttpResponse { get; set; } } -/// Remote MCP server name for a passive OAuth status probe. +/// One ordered workflow progress line. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthProbeRequest +public sealed class WorkflowLogLine { - /// Exact owned receipt identity; probing never activates a dormant installation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Progress line kind. + [JsonPropertyName("kind")] + public WorkflowLogLineKind Kind { get; set; } - /// Name of the configured remote MCP server to probe. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public required string ServerName { get; set; } + /// Monotonic sequence number within the workflow run. + [JsonPropertyName("seq")] + public long Seq { get; set; } + + /// Progress text. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; } -/// Remote MCP server name for a passive OAuth status probe. +/// Parameters for recording workflow progress. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthProbeRequestWithSession +internal sealed class WorkflowLogRequest { - /// Exact owned receipt identity; probing never activates a dormant installation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// Name of the configured remote MCP server to probe. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Ordered progress lines to append. + [JsonPropertyName("lines")] + public IList Lines { get => field ??= []; set; } + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Honest terminal cancellation result; persistence or recovery failures remain RPC errors. +/// Result of one workflow-scoped subagent call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionMcpOauthCancelLoginResult +public sealed class WorkflowAgentResult { - /// True after cancellation settles, false when the original login already connected successfully. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } + /// Agent result, omitted when the agent produced no result. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } } -/// Targets only the original prepared/applying owned login on this exact session requester. +/// Options for one workflow-scoped subagent call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpOauthCancelLoginRequest +public sealed class WorkflowAgentOptions { - /// The same authoritative installation identity supplied during preparation. - [JsonPropertyName("expectedInstallationId")] - public string ExpectedInstallationId { get; set; } = string.Empty; + /// Optional built-in or custom agent name whose definition configures the subagent. + [JsonPropertyName("agent")] + public string? Agent { get; set; } - /// Runtime-issued login handle known before the effectful login request begins. - [JsonPropertyName("loginId")] - public string LoginId { get; set; } = string.Empty; + /// Optional context tier override for the subagent. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Optional label distinguishing otherwise identical memoized agent calls. + [JsonPropertyName("label")] + public string? Label { get; set; } -/// Indicates whether the pending MCP OAuth response was accepted. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthRespondResult -{ - /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// Optional model identifier for the subagent. + [JsonPropertyName("model")] + public string? Model { get; set; } -/// Pending MCP OAuth request id to respond to. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthRespondRequest -{ - /// OAuth request identifier from the mcp.oauth_required event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Optional reasoning effort override for the subagent. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional JSON Schema for structured agent output. + [JsonPropertyName("schema")] + public JsonElement? Schema { get; set; } } -/// Indicates whether the pending MCP headers refresh response was accepted. +/// Parameters for one workflow-scoped subagent call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpHeadersHandlePendingHeadersRefreshRequestResult +internal sealed class WorkflowAgentRequest { - /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. - [JsonPropertyName("success")] - public bool Success { get; set; } -} - -/// Host response: supply dynamic headers or decline this refresh. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestHeaders), "headers")] -[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestNone), "none")] -[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestError), "error")] -public partial class McpHeadersHandlePendingHeadersRefreshRequest -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} - + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; -/// The headers variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpHeadersHandlePendingHeadersRefreshRequestHeaders : McpHeadersHandlePendingHeadersRefreshRequest -{ - /// - [JsonIgnore] - public override string Kind => "headers"; + /// Subagent execution options. + [JsonPropertyName("opts")] + public WorkflowAgentOptions Opts { get => field ??= new(); set; } - /// Headers to overlay onto the MCP request. Dynamic headers override static config headers but do not replace SDK-managed request headers. - [JsonPropertyName("headers")] - public required IDictionary Headers { get; set; } + /// Prompt to send to the subagent. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Optional lifetime in milliseconds for these returned headers. The runtime clamps its configured cache lifetime to this value. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ttlMs")] - public long? TtlMs { get; set; } -} + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; -/// The none variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpHeadersHandlePendingHeadersRefreshRequestNone : McpHeadersHandlePendingHeadersRefreshRequest -{ - /// - [JsonIgnore] - public override string Kind => "none"; + /// Workflow run identifier that owns the subagent. + [JsonPropertyName("workflowRunId")] + public string WorkflowRunId { get; set; } = string.Empty; } -/// The error variant of . +/// Result of reading a workflow journal entry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpHeadersHandlePendingHeadersRefreshRequestError : McpHeadersHandlePendingHeadersRefreshRequest +public sealed class WorkflowJournalGetResult { - /// - [JsonIgnore] - public override string Kind => "error"; + /// Whether the journal contained the requested key. + [JsonPropertyName("hit")] + public bool Hit { get; set; } - /// Host credential broker failure, denial, or revocation reason. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Cached JSON result. The hit field distinguishes a cached JSON null from a miss. + [JsonPropertyName("resultJson")] + public JsonElement? ResultJson { get; set; } } -/// MCP headers refresh request id and the host response. +/// Parameters for reading a workflow journal entry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpHeadersHandlePendingHeadersRefreshRequestRequest +internal sealed class WorkflowJournalGetRequest { - /// Headers refresh request identifier from mcp.headers_refresh_required. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// Host response: supply dynamic headers or decline this refresh. - [JsonPropertyName("result")] - public McpHeadersHandlePendingHeadersRefreshRequest Result { get => field ??= new(); set; } + /// Namespaced journal key. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource metadata. +/// Parameters for storing a workflow journal entry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsResourceContent +internal sealed class WorkflowJournalPutRequest { - /// Resource-level metadata (CSP, permissions, etc.). - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// Base64-encoded binary content. - [JsonPropertyName("blob")] - public string? Blob { get; set; } + /// Namespaced journal key. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// MIME type of the content. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// JSON result to memoize. + [JsonPropertyName("resultJson")] + public JsonElement ResultJson { get; set; } - /// Text content (e.g. HTML). - [JsonPropertyName("text")] - public string? Text { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// The resource URI (typically ui://...). - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Resource contents returned by the MCP server. +/// The session's authoritative model snapshot. Auto preference fields are configuration for the virtual `auto` model and do not change the selected model identifier. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsReadResourceResult +public sealed class CurrentModel { - /// Resource contents returned by the server. - [JsonPropertyName("contents")] - public IList Contents { get => field ??= []; set; } -} + /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. + [JsonPropertyName("activatingAutoTier")] + public AutoTier? ActivatingAutoTier { get; set; } -/// MCP server and resource URI to fetch. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsReadResourceRequest -{ - /// Name of the MCP server hosting the resource. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Auto preference currently committed for the session. This can remain available while another model is selected so a later switch to `auto` can reuse it. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Context tier for models that support multiple context-window sizes. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } - /// Resource URI (typically ui://...). - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; -} + /// Currently active model identifier. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } -/// App-callable tools from the named MCP server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsListToolsResult -{ - /// App-callable tools from the server. - [JsonPropertyName("tools")] - public IList> Tools { get => field ??= []; set; } -} + /// Latest unclaimed Auto preference waiting for a future user turn. Null means the pending request is returning to provider-default routing. + [JsonPropertyName("pendingAutoTier")] + public AutoTier? PendingAutoTier { get; set; } -/// MCP server to list app-callable tools for. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsListToolsRequest -{ - /// **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. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("originServerName")] - public string OriginServerName { get; set; } = string.Empty; + /// Captured base model to restore when leaving plan mode. Omitted outside plan mode or when no plan override has captured a base model. Persistent agent model requirements apply to this model rather than the temporary plan model. + [JsonPropertyName("planBaseModelId")] + public string? PlanBaseModelId { get; set; } - /// MCP server hosting the app. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Provider of planBaseModelId, when that saved selection is provider-qualified. + [JsonPropertyName("planBaseProviderId")] + public string? PlanBaseProviderId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Provider selected for this model. Together with modelId, identifies a catalog entry even when providers serve the same model. Omitted for unattributed legacy selections. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } } -/// MCP server, tool name, and arguments to invoke from an MCP App view. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsCallToolRequest +internal sealed class SessionModelGetCurrentRequest { - /// Tool arguments. - [JsonPropertyName("arguments")] - public IDictionary? Arguments { get; set; } - - /// **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. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("originServerName")] - public string OriginServerName { get; set; } = string.Empty; - - /// MCP server hosting the tool. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// MCP tool name. - [JsonPropertyName("toolName")] - public string ToolName { get; set; } = string.Empty; } -/// Host context advertised to MCP App guests. +/// RPC data type for ModelSwitchConfirmation operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsSetHostContextDetails +public sealed class ModelSwitchConfirmation { - /// Display modes the host supports. - [JsonPropertyName("availableDisplayModes")] - public IList? AvailableDisplayModes { get; set; } - - /// Current display mode (SEP-1865). - [JsonPropertyName("displayMode")] - public McpAppsSetHostContextDetailsDisplayMode? DisplayMode { get; set; } - - /// BCP-47 locale, e.g. 'en-US'. - [JsonPropertyName("locale")] - public string? Locale { get; set; } - - /// Platform type for responsive design. - [JsonPropertyName("platform")] - public McpAppsSetHostContextDetailsPlatform? Platform { get; set; } - - /// UI theme preference per SEP-1865. - [JsonPropertyName("theme")] - public McpAppsSetHostContextDetailsTheme? Theme { get; set; } + /// Current conversation token count before switching models. + [JsonPropertyName("currentTokens")] + public double CurrentTokens { get; set; } - /// IANA timezone, e.g. 'America/New_York'. - [JsonPropertyName("timeZone")] - public string? TimeZone { get; set; } + /// Target model token limit used by the compaction preflight. + [JsonPropertyName("targetLimit")] + public double TargetLimit { get; set; } - /// Host application identifier. - [JsonPropertyName("userAgent")] - public string? UserAgent { get; set; } + /// Display name of the model that requires compaction confirmation. + [JsonPropertyName("targetModelDisplayName")] + public string TargetModelDisplayName { get; set; } = string.Empty; } -/// Host context to advertise to MCP App guests. +/// The model identifier active on the session after the switch. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsSetHostContextRequest +public sealed class ModelSwitchToResult { - /// Host context advertised to MCP App guests. - [JsonPropertyName("context")] - public McpAppsSetHostContextDetails Context { get => field ??= new(); set; } + /// Compaction confirmation projection when status is confirmation_required. + [JsonPropertyName("confirmation")] + public ModelSwitchConfirmation? Confirmation { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// True when the switch was deferred (enqueued as a cancellable `/model` command) because a turn was active or another model change was already queued, rather than applied immediately. When true, the session's live model is unchanged until the queued change drains. + [JsonPropertyName("deferred")] + public bool? Deferred { get; set; } -/// Current host context. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsHostContextDetails -{ - /// Display modes the host supports. - [JsonPropertyName("availableDisplayModes")] - public IList? AvailableDisplayModes { get; set; } + /// Deprecation warnings associated with the selected model or options. + [JsonPropertyName("deprecationWarnings")] + public IList? DeprecationWarnings { get; set; } - /// Current display mode (SEP-1865). - [JsonPropertyName("displayMode")] - public McpAppsHostContextDetailsDisplayMode? DisplayMode { get; set; } + /// User-facing outcome message for the model switch. + [JsonPropertyName("message")] + public string? Message { get; set; } - /// BCP-47 locale, e.g. 'en-US'. - [JsonPropertyName("locale")] - public string? Locale { get; set; } + /// Currently active model identifier after the switch. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } - /// Platform type for responsive design. - [JsonPropertyName("platform")] - public McpAppsHostContextDetailsPlatform? Platform { get; set; } + /// Authoritative model and Auto preference state after an immediate switch. For deferred switches this remains the current state until the queued change drains. + [JsonPropertyName("modelState")] + public CurrentModel? ModelState { get; set; } - /// UI theme preference per SEP-1865. - [JsonPropertyName("theme")] - public McpAppsHostContextDetailsTheme? Theme { get; set; } + /// Persistence failure encountered after applying the model switch. + [JsonPropertyName("persistenceError")] + public string? PersistenceError { get; set; } - /// IANA timezone, e.g. 'America/New_York'. - [JsonPropertyName("timeZone")] - public string? TimeZone { get; set; } + /// Stable queue item identifier when this request was enqueued. Remains present if the item drains before the response is returned. + [JsonPropertyName("queueId")] + public string? QueueId { get; set; } - /// Host application identifier. - [JsonPropertyName("userAgent")] - public string? UserAgent { get; set; } -} + /// Lifecycle result for the requested switch. + [JsonPropertyName("status")] + public string? Status { get; set; } -/// Current host context advertised to MCP App guests. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsHostContext -{ - /// Current host context. - [JsonPropertyName("context")] - public McpAppsHostContextDetails Context { get => field ??= new(); set; } + /// User-facing warning produced while applying the model switch. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Identifies the target session. +/// Filesystem and environment context used to resolve model-picker settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpAppsGetHostContextRequest +public sealed class ModelPickerSettingsContext { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional Copilot configuration directory containing persisted settings. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } + + /// Environment variables consulted while resolving model-picker settings. + [JsonPropertyName("environment")] + public IDictionary Environment { get => field ??= new Dictionary(); set; } + + /// User home directory used when resolving persisted settings. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; } -/// Capability negotiation snapshot. +/// RPC data type for ModelPickerPersistence operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsDiagnoseCapability +public sealed class ModelPickerPersistenceRequest { - /// Whether the runtime advertises `extensions.io.modelcontextprotocol/ui` to MCP servers. - [JsonPropertyName("advertised")] - public bool Advertised { get; set; } + /// Whether context tier was explicitly selected and should be persisted. + [JsonPropertyName("contextTierExplicit")] + public bool? ContextTierExplicit { get; set; } - /// Whether the MCP_APPS feature flag (or COPILOT_MCP_APPS env override) is on. - [JsonPropertyName("featureFlagEnabled")] - public bool FeatureFlagEnabled { get; set; } + /// Whether reasoning effort was explicitly selected and should be persisted. + [JsonPropertyName("reasoningEffortExplicit")] + public bool? ReasoningEffortExplicit { get; set; } - /// Whether the session has the `mcp-apps` capability. - [JsonPropertyName("sessionHasMcpApps")] - public bool SessionHasMcpApps { get; set; } + /// Filesystem and environment context used to resolve settings persistence. + [JsonPropertyName("settingsContext")] + public ModelPickerSettingsContext SettingsContext { get => field ??= new(); set; } } -/// What the server returned for this session. +/// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsDiagnoseServer +public sealed class ModelSwitchToRequest { - /// Whether the named server is currently connected. - [JsonPropertyName("connected")] - public bool Connected { get; set; } - - /// Up to 5 tool names with `_meta.ui` for quick inspection. - [JsonPropertyName("sampleToolNames")] - public IList SampleToolNames { get => field ??= []; set; } + /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Total tools returned by the server's tools/list. - [JsonPropertyName("toolCount")] - public double ToolCount { get; set; } + /// Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. + [JsonPropertyName("compactionDecision")] + public string? CompactionDecision { get; set; } - /// Tools whose `_meta.ui` is populated (resourceUri and/or visibility set). - [JsonPropertyName("toolsWithUiMeta")] - public double ToolsWithUiMeta { get; set; } -} + /// 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 ContextTier? ContextTier { get; set; } -/// Diagnostic snapshot of MCP Apps wiring for the named server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsDiagnoseResult -{ - /// Capability negotiation snapshot. - [JsonPropertyName("capability")] - public McpAppsDiagnoseCapability Capability { get => field ??= new(); set; } + /// When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). + [JsonPropertyName("deferIfModelChangeQueued")] + public bool? DeferIfModelChangeQueued { get; set; } - /// What the server returned for this session. - [JsonPropertyName("server")] - public McpAppsDiagnoseServer Server { get => field ??= new(); set; } -} + /// Override individual model capabilities resolved by the runtime. + [JsonPropertyName("modelCapabilities")] + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } -/// MCP server to diagnose MCP Apps wiring for. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsDiagnoseRequest -{ - /// MCP server to probe. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Settings scope used when persisting the selected model. + [JsonPropertyName("modelChangeScope")] + public string? ModelChangeScope { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. + [JsonPropertyName("modelId")] + public required string ModelId { get; set; } -/// MCP resource content with URI, optional MIME type, text or base64 blob, and resource metadata. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceContent -{ - /// Resource-level metadata (CSP, permissions, etc.). - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } + /// Optional settings context and explicit-override flags used to persist a picker selection. + [JsonPropertyName("pickerPersistence")] + public ModelPickerPersistenceRequest? PickerPersistence { get; set; } - /// Base64-encoded binary content. - [JsonPropertyName("blob")] - public string? Blob { get; set; } + /// Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } - /// MIME type of the content. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Text content (e.g. HTML). - [JsonPropertyName("text")] - public string? Text { get; set; } + /// Reasoning summary mode to request for supported model clients. + [JsonPropertyName("reasoningSummary")] + public ReasoningSummary? ReasoningSummary { get; set; } - /// The resource URI. - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; -} + /// Optional repository settings scope to persist after the switch commits. + [JsonPropertyName("repoScope")] + public string? RepoScope { get; set; } -/// Resource contents returned by the MCP server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourcesReadResult -{ - /// Resource contents returned by the server. - [JsonPropertyName("contents")] - public IList Contents { get => field ??= []; set; } -} + /// Require the target to be currently available and enabled before applying the switch. + [JsonPropertyName("requireAvailable")] + public bool? RequireAvailable { get; set; } -/// MCP server and resource URI to fetch. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpResourcesReadRequest -{ - /// Name of the MCP server hosting the resource. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// When true, evaluate context-window compaction policy before applying the switch. + [JsonPropertyName("runCompactionPreflight")] + public bool? RunCompactionPreflight { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. + [JsonPropertyName("source")] + public ModelChangeSource? Source { get; set; } - /// Resource URI. - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// Output verbosity level to request for supported models. + [JsonPropertyName("verbosity")] + public Verbosity? Verbosity { get; set; } } -/// Standard MCP resource annotations plus preserved non-standard annotation fields. +/// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceAnnotations +internal sealed class ModelSwitchToRequestWithSession { - /// Server-provided non-standard annotation fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Intended audience roles for this resource. - [JsonPropertyName("audience")] - public IList? Audience { get; set; } - - /// Last-modified timestamp hint. - [JsonPropertyName("lastModified")] - public string? LastModified { get; set; } + /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Priority hint for model/client use. - [JsonPropertyName("priority")] - public double? Priority { get; set; } -} + /// Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. + [JsonPropertyName("compactionDecision")] + public string? CompactionDecision { get; set; } -/// A resource icon descriptor plus preserved non-standard icon fields. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceIcon -{ - /// Server-provided non-standard icon fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } + /// 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 ContextTier? ContextTier { get; set; } - /// Icon MIME type, when known. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). + [JsonPropertyName("deferIfModelChangeQueued")] + public bool? DeferIfModelChangeQueued { get; set; } - /// Icon sizes hint. - [JsonPropertyName("sizes")] - public string? Sizes { get; set; } + /// Override individual model capabilities resolved by the runtime. + [JsonPropertyName("modelCapabilities")] + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } - /// Icon URI. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; + /// Settings scope used when persisting the selected model. + [JsonPropertyName("modelChangeScope")] + public string? ModelChangeScope { get; set; } - /// Theme hint for this icon. - [JsonPropertyName("theme")] - public string? Theme { get; set; } -} + /// Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; -/// An MCP resource descriptor (spec `Resource`): URI, name, and optional title, description, MIME type, size, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResource -{ - /// Resource-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } + /// Optional settings context and explicit-override flags used to persist a picker selection. + [JsonPropertyName("pickerPersistence")] + public ModelPickerPersistenceRequest? PickerPersistence { get; set; } - /// Server-provided non-standard descriptor fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } + /// Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } - /// Model/client annotations associated with this resource. - [JsonPropertyName("annotations")] - public McpResourceAnnotations? Annotations { get; set; } + /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Optional description of what this resource represents. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Reasoning summary mode to request for supported model clients. + [JsonPropertyName("reasoningSummary")] + public ReasoningSummary? ReasoningSummary { get; set; } - /// Icons associated with this resource. - [JsonPropertyName("icons")] - public IList? Icons { get; set; } + /// Optional repository settings scope to persist after the switch commits. + [JsonPropertyName("repoScope")] + public string? RepoScope { get; set; } - /// MIME type of the resource, if known. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Require the target to be currently available and enabled before applying the switch. + [JsonPropertyName("requireAvailable")] + public bool? RequireAvailable { get; set; } - /// The programmatic name of the resource. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// When true, evaluate context-window compaction policy before applying the switch. + [JsonPropertyName("runCompactionPreflight")] + public bool? RunCompactionPreflight { get; set; } - /// Resource size in bytes, when known. - [JsonPropertyName("size")] - public long? Size { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Optional human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. + [JsonPropertyName("source")] + public ModelChangeSource? Source { get; set; } - /// The resource URI (e.g. ui://... or file:///...). - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// Output verbosity level to request for supported models. + [JsonPropertyName("verbosity")] + public Verbosity? Verbosity { get; set; } } -/// One page of resources advertised by the named MCP server. +/// Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourcesListResult +public sealed class ModelSwitchAutoTierResult { - /// Opaque cursor for the next page, if the server has more resources. - [JsonPropertyName("nextCursor")] - public string? NextCursor { get; set; } + /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. + [JsonPropertyName("activatingAutoTier")] + public AutoTier? ActivatingAutoTier { get; set; } - /// Resources advertised by the server (proxied MCP `resources/list`). - [JsonPropertyName("resources")] - public IList Resources { get => field ??= []; set; } + /// Auto preference currently committed for the session. + [JsonPropertyName("effectiveAutoTier")] + public AutoTier? EffectiveAutoTier { get; set; } + + /// Latest unclaimed Auto preference waiting for a future user turn. + [JsonPropertyName("pendingAutoTier")] + public AutoTier? PendingAutoTier { get; set; } + + /// Immediate request status. `pending` means accepted but not committed. + [JsonPropertyName("status")] + public ModelSwitchAutoTierStatus Status { get; set; } + + /// Earlier unclaimed preference replaced by this request. This can be present with either status, including when selecting the effective preference cancels pending work. + [JsonPropertyName("supersededAutoTier")] + public AutoTier? SupersededAutoTier { get; set; } } -/// MCP server whose resources to enumerate. +/// An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpResourcesListRequest +internal sealed class ModelSwitchAutoTierRequest { - /// Opaque MCP pagination cursor from a prior `nextCursor` value. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } - - /// Name of the MCP server whose resources to enumerate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Auto preference to activate when a future user turn using the `auto` model safely mints a replacement model and token pair. Pass null to return to provider-default Auto routing. + [JsonPropertyName("autoTier")] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public AutoTier? AutoTier { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Origin to record on the effective `session.model_change` event. Defaults to `sdk` when omitted. + [JsonPropertyName("source")] + public ModelChangeSource? Source { get; set; } } -/// An MCP resource template descriptor (spec `ResourceTemplate`): an RFC 6570 URI template, name, and optional title, description, MIME type, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. +/// Managed, repository, and CLI model overrides to overlay onto the session at startup. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceTemplate +internal sealed class ModelApplyStartupOverlayRequest { - /// Resource-template-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } + /// Effective default Auto routing preference from user and managed settings. Applies only to fresh sessions and never replaces a per-session selection. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Server-provided non-standard descriptor fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } + /// Model explicitly selected by the CLI, when provided. + [JsonPropertyName("cliModel")] + public string? CliModel { get; set; } - /// Model/client annotations associated with this template. - [JsonPropertyName("annotations")] - public McpResourceAnnotations? Annotations { get; set; } + /// Whether the overlay is being applied while resuming a deferred session. + [JsonPropertyName("deferredResume")] + public bool? DeferredResume { get; set; } - /// Optional description of what this template is for. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Model required by device-managed policy, when configured. + [JsonPropertyName("deviceManagedModel")] + public string? DeviceManagedModel { get; set; } - /// Icons associated with resources matching this template. - [JsonPropertyName("icons")] - public IList? Icons { get; set; } + /// Context tier paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. + [JsonPropertyName("managedContextTier")] + public string? ManagedContextTier { get; set; } - /// MIME type for resources matching this template, if uniform. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Reasoning effort paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. + [JsonPropertyName("managedReasoningEffort")] + public string? ManagedReasoningEffort { get; set; } - /// The programmatic name of the resource template. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Startup default model from the enterprise policy helper, when configured. Weakest of the managed sources: it applies only when neither device nor server policy names a model, and an explicit user selection still wins. + [JsonPropertyName("policyHelperModel")] + public string? PolicyHelperModel { get; set; } - /// Optional human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Auto routing preference selected by repository settings, when configured. Applied only when the overlay selects the Auto model; beside a concrete model it stays dormant. + [JsonPropertyName("repoAutoTier")] + public string? RepoAutoTier { get; set; } - /// An RFC 6570 URI template for constructing resource URIs. - [JsonPropertyName("uriTemplate")] - public string UriTemplate { get; set; } = string.Empty; -} + /// Context tier selected by repository settings, when configured. + [JsonPropertyName("repoContextTier")] + public string? RepoContextTier { get; set; } -/// One page of resource templates advertised by the named MCP server. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourcesListTemplatesResult -{ - /// Opaque cursor for the next page, if the server has more resource templates. - [JsonPropertyName("nextCursor")] - public string? NextCursor { get; set; } + /// Model selected by repository settings, when configured. + [JsonPropertyName("repoModel")] + public string? RepoModel { get; set; } - /// Resource templates advertised by the server (proxied MCP `resources/templates/list`). - [JsonPropertyName("resourceTemplates")] - public IList ResourceTemplates { get => field ??= []; set; } -} + /// Provider owning the repository-selected model. Omitted repository provider identity retains legacy bare-model behavior. + [JsonPropertyName("repoModelProviderId")] + public string? RepoModelProviderId { get; set; } -/// MCP server whose resource templates to enumerate. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpResourcesListTemplatesRequest -{ - /// Opaque MCP pagination cursor from a prior `nextCursor` value. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } + /// Reasoning effort selected by repository settings, when configured. + [JsonPropertyName("repoReasoningEffort")] + public string? RepoReasoningEffort { get; set; } - /// Name of the MCP server whose resource templates to enumerate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Model required by server-managed policy, when configured. + [JsonPropertyName("serverManagedModel")] + public string? ServerManagedModel { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// An argument accepted by an MCP prompt. +/// RPC data type for SessionModelClearStartupSeed operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptArgument +internal sealed class SessionModelClearStartupSeedResult { - /// Argument-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard argument fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Description of the argument. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Name of the argument. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Whether the argument is required; omission is distinct from false. - [JsonPropertyName("required")] - public bool? Required { get; set; } + /// Gets or sets the cleared value. + [JsonPropertyName("cleared")] + public bool Cleared { get; set; } } -/// An MCP prompt icon with standard size hints and preserved non-standard fields. +/// RPC data type for SessionModelClearStartupSeed operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptIcon +internal sealed class SessionModelClearStartupSeedRequest { - /// Server-provided non-standard icon fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Icon MIME type, when known. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } - - /// Icon sizes, such as `48x48` or `any`. - [JsonPropertyName("sizes")] - public IList? Sizes { get; set; } + /// Gets or sets the expectedModel value. + [JsonPropertyName("expectedModel")] + public string ExpectedModel { get; set; } = string.Empty; - /// Icon URI. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; + /// Provider captured with the startup seed; omission matches only an unqualified seed. + [JsonPropertyName("expectedProviderId")] + public string? ExpectedProviderId { get; set; } - /// Theme hint for this icon. - [JsonPropertyName("theme")] - public string? Theme { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// An MCP prompt descriptor. Server-provided non-standard fields are exposed under `additionalProperties`. +/// The applied host allowlist and effective session model policy after intersection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPrompt +public sealed class ModelSetAllowedModelsResult { - /// Prompt-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard descriptor fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Arguments accepted by the prompt. - [JsonPropertyName("arguments")] - public IList? Arguments { get; set; } - - /// Description of what this prompt provides. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Normalized host allowlist. Omitted when the host restriction was cleared, or when a relay client does not return the host policy. + [JsonPropertyName("allowedModels")] + public IList? AllowedModels { get; set; } - /// Icons associated with this prompt. - [JsonPropertyName("icons")] - public IList? Icons { get; set; } + /// Effective exact IDs or repository policy patterns after applying the host restriction. Omitted by relay clients that do not return the host policy. + [JsonPropertyName("effectiveAllowedModels")] + public IList? EffectiveAllowedModels { get; set; } - /// The programmatic name of the prompt. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Effective deterministic fallback model, when the policy defines one. + [JsonPropertyName("fallbackModel")] + public string? FallbackModel { get; set; } - /// Human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Selected session model after reconciling a now-disallowed concrete selection. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } } -/// One page of prompts advertised by the named MCP server. +/// Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptsListResult +internal sealed class ModelSetAllowedModelsRequest { - /// MCP result metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard result fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Opaque cursor for the next page, if the server has more prompts. - [JsonPropertyName("nextCursor")] - public string? NextCursor { get; set; } + /// Exact model IDs to permit, or null to clear the host restriction. + [JsonPropertyName("allowedModels")] + public IList? AllowedModels { get; set; } - /// Prompts advertised by the server. - [JsonPropertyName("prompts")] - public IList Prompts { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// MCP server whose prompts to enumerate. +/// 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPromptsListRequest +public sealed class ModelSetReasoningEffortResult { - /// Opaque MCP pagination cursor from a prior `nextCursor` value. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } + /// Reasoning effort level recorded on the session after the update. + [JsonPropertyName("reasoningEffort")] + public string ReasoningEffort { get; set; } = string.Empty; +} - /// Name of the MCP server whose prompts to enumerate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; +/// Reasoning effort level to apply to the currently selected model. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ModelSetReasoningEffortRequest +{ + /// Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. + [JsonPropertyName("reasoningEffort")] + public string ReasoningEffort { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// An MCP prompt message with opaque JSON content preserved without flattening or content-type filtering. +/// Reasoning-summaries presentation policy for the session's current model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptMessage +public sealed class ModelGetReasoningSummariesResult { - /// Message-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } + /// Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + [JsonPropertyName("clearRedundantSetting")] + public bool ClearRedundantSetting { get; set; } - /// Server-provided non-standard message fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } + /// Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. + [JsonPropertyName("experimentSettled")] + public bool ExperimentSettled { get; set; } - /// The original MCP content block, including nested metadata and unfamiliar content types. - [JsonPropertyName("content")] - public JsonElement Content { get; set; } + /// Whether the selected model shows reasoning summaries by default. + [JsonPropertyName("modelDefaultShowsSummaries")] + public bool ModelDefaultShowsSummaries { get; set; } - /// The role of the message sender. - [JsonPropertyName("role")] - public McpPromptRole Role { get; set; } -} + /// False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. + [JsonPropertyName("ready")] + public bool Ready { get; set; } -/// Prompt messages returned by the MCP server without sending them to the model. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptsGetResult -{ - /// MCP result metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } + /// Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. + [JsonPropertyName("sessionShowsSummaries")] + public bool SessionShowsSummaries { get; set; } - /// Server-provided non-standard result fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } + /// Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + [JsonPropertyName("showHiddenHint")] + public bool ShowHiddenHint { get; set; } - /// Description of the prompt. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Whether the selected model emits reasoning headers. + [JsonPropertyName("showReasoningHeaders")] + public bool ShowReasoningHeaders { get; set; } - /// Ordered prompt messages. - [JsonPropertyName("messages")] - public IList Messages { get => field ??= []; set; } + /// Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + [JsonPropertyName("visibility")] + public bool? Visibility { get; set; } } -/// MCP server, prompt name, and optional string-valued arguments. +/// Host presentation state the reasoning-summaries policy depends on. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPromptsGetRequest +internal sealed class ModelGetReasoningSummariesRequest { - /// String-valued arguments to pass to the prompt. - [JsonPropertyName("arguments")] - public IDictionary? Arguments { get; set; } - - /// The programmatic name of the prompt. - [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("promptName")] - public string PromptName { get; set; } = string.Empty; - - /// Name of the MCP server hosting the prompt. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [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("serverName")] - public string ServerName { get; set; } = string.Empty; + /// The host's persisted `showReasoning` user setting, omitted when unset. + [JsonPropertyName("persistedShowReasoning")] + public bool? PersistedShowReasoning { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Whether the host is currently showing reasoning summaries. Defaults to false. + [JsonPropertyName("summariesVisible")] + public bool? SummariesVisible { get; set; } } -/// MCP diagnostic source configuration. +/// Availability of a server-advertised routing preference. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDiagnosticSourceConfiguration +public sealed class AutoTierStatus { - /// Threshold to apply to MCP diagnostic producers in this session. - [JsonPropertyName("level")] - public DiagnosticLogLevel Level { get; set; } + /// Whether the provider permits selecting this preference. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Human-readable explanation of availability. + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// Extensible machine-readable unavailability reason. + [JsonPropertyName("reason")] + public string? Reason { get; set; } } -/// Typed diagnostic source configuration. At least one source is required by diagnostics configuration methods. +/// A server-advertised routing preference. Identifiers and execution types are extensible. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiagnosticSourcesConfiguration +public sealed class AutoTierDescriptor { - /// MCP diagnostic capture threshold. Omit to leave the current threshold unchanged. - [JsonPropertyName("mcp")] - public McpDiagnosticSourceConfiguration? Mcp { get; set; } + /// Description displayed beside the preference. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Human-readable label, not a routing identifier. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + /// Opaque routing identifier transmitted unchanged to the provider. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Current account-specific availability. + [JsonPropertyName("status")] + public AutoTierStatus Status { get => field ??= new(); set; } + + /// Execution kind; this client supports `auto` preferences on the Auto model. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; } -/// Per-source session diagnostics configuration. +/// Account-bound discovery metadata for the virtual `auto` model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiagnosticsConfiguration +public sealed class AutoTierMetadata { - /// Diagnostic thresholds keyed by supported source. - [JsonPropertyName("sources")] - public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } + /// Provider-default preference, used only when no explicit preference exists. + [JsonPropertyName("defaultTier")] + public string DefaultTier { get; set; } = string.Empty; + + /// Provider that supplied this metadata, when the catalog is provider-attributed. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Routing preferences in the server's presentation order. + [JsonPropertyName("tiers")] + public IList Tiers { get => field ??= []; set; } } -/// Patch session diagnostic thresholds for explicitly supplied sources. +/// Cost-category metadata for a CAPI model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiagnosticsConfigureRequest +public sealed class SessionModelPriceCategory { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// CAPI model identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Sources to configure. At least one supported source must be supplied. - [JsonPropertyName("sources")] - public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } + /// Cost category assigned to the model. + [JsonPropertyName("priceCategory")] + public ModelPickerPriceCategory PriceCategory { get; set; } } -/// One retained session-scoped diagnostic record. Potentially content-bearing diagnostic data is opt-in and must not be exported automatically as telemetry. -/// Polymorphic base type discriminated by source. +/// One model provider available to the session — the model analog of the account `ProviderDescriptor`. Opaque id/label/kind plus a stable ordering; central code never branches on kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "source", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(DiagnosticEntryMcp), "mcp")] -public partial class DiagnosticEntry +public sealed class ModelProviderDescriptor { - /// The type discriminator. - [JsonPropertyName("source")] - public virtual string Source { get; set; } = string.Empty; -} + /// Opaque, stable provider id, stamped onto every model this provider returns. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + /// The neutral provider kind. + [JsonPropertyName("kind")] + public ModelProviderKind Kind { get; set; } -/// MCP-specific detail for a source-discriminated diagnostic entry. + /// Human-readable menu label, owned by the runtime so every consumer renders identical text. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; + + /// Stable ordering key for presenting providers in a deterministic sequence. + [JsonPropertyName("ordering")] + public long Ordering { get; set; } +} + +/// The list of models available to this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDiagnosticDetails +public sealed class SessionModelList { - /// Fresh identifier for the MCP connection attempt, including failed starts. - [JsonPropertyName("connectionId")] - public string ConnectionId { get; set; } = string.Empty; + /// Ordered Auto routing preferences discovered for this session's account. + [JsonPropertyName("auto")] + public AutoTierMetadata? Auto { get; set; } - /// Serialized diagnostic detail. Protocol and HTTP records use JSON when detail is present. - [JsonPropertyName("data")] - public string? Data { get; set; } + /// Available models, ordered with the most preferred default first. Includes both Copilot (CAPI) models and any registry BYOK models; a BYOK model appears under its provider-qualified selection id (`provider/id`). + [JsonPropertyName("list")] + public IList List { get => field ??= []; set; } - /// Protocol-frame direction when kind is protocol. - [JsonPropertyName("direction")] - public McpDiagnosticDirection? Direction { get; set; } + /// Cost categories for the full CAPI catalog, including picker-disabled models that Auto may select. Metadata only; entries absent from `list` are not manually selectable. + [JsonPropertyName("modelPriceCategories")] + public IList? ModelPriceCategories { get; set; } - /// Diagnostic record category. - [JsonPropertyName("kind")] - public McpDiagnosticKind Kind { get; set; } + /// The model providers available to this session, in ordering order, resolved from the account roster; empty when no provider is entitled (logged out / seatless). Each model in `list` carries its own provider reference; this roster gives the deterministic provider sequence and lets a consumer group by provider without deriving ordering from the model list. Central code never branches on a provider kind. + [JsonPropertyName("providers")] + public IList? Providers { get; set; } - /// Configured MCP server name. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Per-quota snapshots returned alongside the model list, keyed by quota type. + [JsonPropertyName("quotaSnapshots")] + public IDictionary? QuotaSnapshots { get; set; } } -/// The mcp variant of . +/// RPC data type for SessionModelList operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class DiagnosticEntryMcp : DiagnosticEntry +public sealed class SessionModelListRequest { - /// - [JsonIgnore] - public override string Source => "mcp"; + /// If true, bypasses the per-session model list cache and re-fetches from CAPI. + [JsonPropertyName("skipCache")] + public bool? SkipCache { get; set; } +} - /// Agent identifier for a subagent host. Omitted for the root agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("agentId")] - public string? AgentId { get; set; } +/// RPC data type for SessionModelListRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionModelListRequestWithSession +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Typed MCP diagnostic detail. - [JsonPropertyName("details")] - public required McpDiagnosticDetails Details { get; set; } + /// If true, bypasses the per-session model list cache and re-fetches from CAPI. + [JsonPropertyName("skipCache")] + public bool? SkipCache { get; set; } +} - /// Severity of this emitted diagnostic record. - [JsonPropertyName("level")] - public required DiagnosticSeverity Level { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionModeGetRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Human-readable diagnostic summary. - [JsonPropertyName("message")] - public required string Message { get; set; } +/// Outcome of a session mode change, including any model switch it triggered and follow-up the host must perform. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModeSetResult +{ + /// Whether the host should arm an interactive continuation after the mode change. + [JsonPropertyName("armInteractiveContinuation")] + public bool? ArmInteractiveContinuation { get; set; } - /// Original byte count when a known-size message or data value was truncated. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("originalBytes")] - public long? OriginalBytes { get; set; } + /// Compaction confirmation required before the mode change can complete. + [JsonPropertyName("confirmation")] + public ModelSwitchConfirmation? Confirmation { get; set; } - /// UTC RFC 3339 timestamp captured at the diagnostic source. - [JsonPropertyName("timestamp")] - public required string Timestamp { get; set; } + /// Whether the host must defer implementing the requested mode change. + [JsonPropertyName("deferImplementation")] + public bool? DeferImplementation { get; set; } - /// Whether message or data was truncated to the record-size bound. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("truncated")] - public bool? Truncated { get; set; } -} + /// Deprecation warnings associated with the model selected by the mode change. + [JsonPropertyName("deprecationWarnings")] + public IList? DeprecationWarnings { get; set; } -/// One cursor-addressed page of retained session diagnostics. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiagnosticsReadResult -{ - /// Opaque cursor for the next independent read. - [JsonPropertyName("cursor")] - public string Cursor { get; set; } = string.Empty; + /// User-facing outcome message for the model switch triggered by the mode change. + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Whether the requested cursor remained within the retained buffer window. - [JsonPropertyName("cursorStatus")] - public DiagnosticCursorStatus CursorStatus { get; set; } + /// Whether the requested mode was applied to the session. False only when an 'expectedMode' precondition did not hold, in which case any model change reported alongside it was still applied. + [JsonPropertyName("modeApplied")] + public bool? ModeApplied { get; set; } - /// Number of records lost before this page when known. Omitted when a buffer generation change makes the count unknowable. - [JsonPropertyName("droppedCount")] - public long? DroppedCount { get; set; } + /// Whether applying the mode changed the active model. + [JsonPropertyName("modelChanged")] + public bool ModelChanged { get; set; } - /// Retained records beginning at the requested cursor. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + /// Lifecycle status of the requested mode change. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; - /// Whether additional retained records follow this page. - [JsonPropertyName("hasMore")] - public bool HasMore { get; set; } + /// User-facing warning produced while applying the mode change. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Cursor-based request for session diagnostics. The default limit is 100 (maximum 500); the default waitMs is zero (maximum 30000). +/// Agent interaction mode to apply to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiagnosticsReadRequest +internal sealed class ModeSetRequest { - /// Opaque cursor returned by an earlier read. Omit to start at the oldest retained record. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } - - /// Maximum number of records to return, from 1 through 500. Omit for 100. - [JsonPropertyName("max")] - public long? Max { get; set; } + /// Explicit response to a model-switch compaction preflight. + [JsonPropertyName("compactionDecision")] + public string? CompactionDecision { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Mode the session must currently be in for the change to apply. When set and the session is in a different mode the request is a no-op and reports status 'unchanged'. + [JsonPropertyName("expectedMode")] + public SessionMode? ExpectedMode { get; set; } - /// Nonempty selection of sources to read. Each source may be listed once. - [JsonPropertyName("sources")] - public IList Sources { get => field ??= []; set; } + /// Session whose plan-mode base state should be inherited. + [JsonPropertyName("inheritPlanBaseFromSessionId")] + public string? InheritPlanBaseFromSessionId { get; set; } - /// Maximum time in milliseconds to wait for a new record, from 0 through 30000. - [JsonPropertyName("waitMs")] - public int? WaitMs { get; set; } -} + /// The session mode the agent is operating in. + [JsonPropertyName("mode")] + public SessionMode Mode { get; set; } -/// Feature detection and hard polling limits for the EXPERIMENTAL session connector API. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorCapabilities -{ - /// Connector API contract version. - [JsonPropertyName("apiVersion")] - public long ApiVersion { get; set; } + /// Whether the selected plan model should be persisted. + [JsonPropertyName("persistPlanSelection")] + public bool? PersistPlanSelection { get; set; } - /// Current session availability. Disabled availability is reported without making a Connector request. - [JsonPropertyName("availability")] - public ConnectorAvailability Availability { get; set; } + /// Settings context used when persisting the selected plan model. + [JsonPropertyName("pickerSettingsContext")] + public ModelPickerSettingsContext? PickerSettingsContext { get; set; } - /// Whether connect and reconnect can return an opaque continuation for bounded consent polling. - [JsonPropertyName("consentContinuation")] - public bool ConsentContinuation { get; set; } + /// Context tier to use with the dedicated plan model. + [JsonPropertyName("planContextTier")] + public string? PlanContextTier { get; set; } - /// Maximum accepted wall-clock deadline in milliseconds for one continuation call. - [JsonPropertyName("maxDeadlineMs")] - public long MaxDeadlineMs { get; set; } + /// Action to perform when leaving plan mode. + [JsonPropertyName("planExitAction")] + public string? PlanExitAction { get; set; } - /// Maximum accepted polling attempts for one continuation call. - [JsonPropertyName("maxPollAttempts")] - public long MaxPollAttempts { get; set; } + /// Dedicated model to use in plan mode, when configured. + [JsonPropertyName("planModel")] + public string? PlanModel { get; set; } - /// Maximum accepted delay in milliseconds between polling attempts. - [JsonPropertyName("maxPollIntervalMs")] - public long MaxPollIntervalMs { get; set; } + /// Whether a dedicated plan model is configured. + [JsonPropertyName("planModelConfigured")] + public bool? PlanModelConfigured { get; set; } - /// Whether callers select a host-owned GitHub account through an opaque selection ID rather than supplying a provider token. - [JsonPropertyName("opaqueAccountSelection")] - public bool OpaqueAccountSelection { get; set; } + /// Provider owning planModel. Omit for legacy bare-model selection. + [JsonPropertyName("planModelProviderId")] + public string? PlanModelProviderId { get; set; } - /// Whether getAccount is supported. Absence means false. - [JsonPropertyName("sessionAccountSelection")] - public bool? SessionAccountSelection { get; set; } + /// Reasoning effort to use with the dedicated plan model. + [JsonPropertyName("planReasoningEffort")] + public string? PlanReasoningEffort { get; set; } - /// Whether reconcile accepts forceConnectorName. Absence means false. - [JsonPropertyName("targetedReconcile")] - public bool? TargetedReconcile { get; set; } -} + /// Whether leaving plan mode should restore the session's previous model. + [JsonPropertyName("restorePlanModel")] + public bool? RestorePlanModel { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsGetCapabilitiesRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Credential-free identity metadata. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthIdentityMetadata -{ - /// Identity host. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// User login. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; - - /// Authentication type. - [JsonPropertyName("type")] - public AuthInfoType Type { get; set; } -} - -/// Session account selection. +/// The session's friendly name, or null when not yet set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorSessionAccount +public sealed class NameGetResult { - /// Opaque session-scoped account selection ID. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; - - /// Credential-free identity metadata. - [JsonPropertyName("authInfo")] - public AuthIdentityMetadata AuthInfo { get => field ??= new(); set; } + /// The session name (user-set or auto-generated), or null if not yet set. + [JsonPropertyName("name")] + public string? Name { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsGetAccountRequest +internal sealed class SessionNameGetRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Account-targeted authorization update required by the Connector service. The account ID is an opaque host routing identifier; no credential is included. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorAuthorizationRequirement -{ - /// Exact opaque account selection that made the Connector request. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; - - /// Stable OAuth scope the selected account must grant. - [JsonPropertyName("scope")] - public ConnectorAuthorizationScope Scope { get; set; } -} - -/// Credential-free Connector catalog entry. +/// New friendly name to apply to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorCatalogEntry +internal sealed class NameSetRequest { - /// Untrusted service description, when present. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Untrusted display label from the service. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; - - /// Optional catalog logo. - [JsonPropertyName("logo")] - public string? Logo { get; set; } - - /// Canonical Connector name used by lifecycle methods. + /// New session name (1–100 characters, trimmed of leading/trailing whitespace). + [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)] + [MaxLength(100)] [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Optional catalog release tag. - [JsonPropertyName("releaseTag")] - public string? ReleaseTag { get; set; } - - /// Opaque stable runtime IDs currently projected into the session for this Connector. - [JsonPropertyName("runtimeServerIds")] - public IList RuntimeServerIds { get => field ??= []; set; } - - /// Current authoritative service connection state. - [JsonPropertyName("status")] - public ConnectorCatalogStatus Status { get; set; } - - /// Optional catalog tier. - [JsonPropertyName("tier")] - public string? Tier { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Validated Connector catalog snapshot cached by the session. +/// Indicates whether the auto-generated summary was applied as the session's name. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorCatalogResult +public sealed class NameSetAutoResult { - /// Validated catalog entries in service order. - [JsonPropertyName("connectors")] - public IList Connectors { get => field ??= []; set; } - - /// Unix epoch milliseconds when this snapshot was accepted. - [JsonPropertyName("refreshedAtMs")] - public long RefreshedAtMs { get; set; } - - /// Monotonically increasing session-local catalog revision. - [JsonPropertyName("revision")] - public long Revision { get; set; } + /// Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. + [JsonPropertyName("applied")] + public bool Applied { get; set; } } -/// Live status of one session-owned MCP projection. +/// Auto-generated session summary to apply as the session's name when no user-set name exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorRuntimeStatus +internal sealed class NameSetAutoRequest { - /// Canonical Connector name that owns this server. - [JsonPropertyName("connectorName")] - public string ConnectorName { get; set; } = string.Empty; - - /// Opaque runtime server ID. - [JsonPropertyName("runtimeServerId")] - public string RuntimeServerId { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Current live MCP host status. - [JsonPropertyName("status")] - public ConnectorMcpStatus Status { get; set; } + /// Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. + [JsonPropertyName("summary")] + public string Summary { get; set; } = string.Empty; } -/// Authoritative session connector state. Account IDs are opaque routing identifiers and credentials are never included. +/// Existence, contents, and resolved path of the session plan file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorStatus +public sealed class PlanReadResult { - /// Opaque account selection pinned to this session, when one has been selected. - [JsonPropertyName("accountId")] - public string? AccountId { get; set; } - - /// Connector API contract version. - [JsonPropertyName("apiVersion")] - public long ApiVersion { get; set; } - - /// Exact selected account and stable scope requiring an authorization update, when proven by the Connector service. - [JsonPropertyName("authorizationRequirement")] - public ConnectorAuthorizationRequirement? AuthorizationRequirement { get; set; } - - /// Current feature and session availability. - [JsonPropertyName("availability")] - public ConnectorAvailability Availability { get; set; } - - /// Latest validated catalog snapshot, when available. - [JsonPropertyName("catalog")] - public ConnectorCatalogResult? Catalog { get; set; } + /// The content of the plan file, or null if it does not exist. + [JsonPropertyName("content")] + public string? Content { get; set; } - /// Number of active opaque connection continuations. - [JsonPropertyName("pendingConnections")] - public long PendingConnections { get; set; } + /// Whether the plan file exists in the workspace. + [JsonPropertyName("exists")] + public bool Exists { get; set; } - /// Live MCP status for every Connector-owned runtime server. - [JsonPropertyName("runtimeServers")] - public IList RuntimeServers { get => field ??= []; set; } + /// Absolute file path of the plan file, or null if workspace is not enabled. + [JsonPropertyName("path")] + public string? Path { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsGetStatusRequest +internal sealed class SessionPlanReadRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Pins a Connector operation to one host-owned GitHub account through its opaque selection ID. Provider tokens are never accepted. +/// Replacement contents to write to the session plan file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorAccountRequest +internal sealed class PlanUpdateRequest { - /// Opaque account selection ID previously returned by an account discovery API. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; + /// The new content for the plan file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Typed result of initiating or continuing a Connector connection. -/// Polymorphic base type discriminated by kind. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ConnectorConnectResultConnected), "connected")] -[JsonDerivedType(typeof(ConnectorConnectResultConsentRequired), "consent_required")] -[JsonDerivedType(typeof(ConnectorConnectResultPending), "pending")] -public partial class ConnectorConnectResult +internal sealed class SessionPlanDeleteRequest { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } - -/// The service is connected and the session MCP graph was reconciled. -/// The connected variant of . +/// A single todo row read from the session SQL `todos` table. All fields are optional because the SQL schema is best-effort and the agent may not have populated every column. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ConnectorConnectResultConnected : ConnectorConnectResult +public sealed class PlanSqlTodosRow { - /// - [JsonIgnore] - public override string Kind => "connected"; + /// Todo creation time, as stored by the session SQL schema's `datetime('now')` default: `YYYY-MM-DD HH:MM:SS` in UTC. Lets clients attribute todos to the work item that created them (e.g. scoping a goal's progress to the todos it produced) rather than to the whole session. + [JsonPropertyName("createdAt")] + public string? CreatedAt { get; set; } - /// Fresh authoritative Connector state after MCP reconciliation. - [JsonPropertyName("status")] - public required ConnectorStatus Status { get; set; } -} + /// Todo description. + [JsonPropertyName("description")] + public string? Description { get; set; } -/// Host-owned consent is required before bounded continuation can complete. -/// The consent_required variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ConnectorConnectResultConsentRequired : ConnectorConnectResult -{ - /// - [JsonIgnore] - public override string Kind => "consent_required"; + /// Todo identifier. + [JsonPropertyName("id")] + public string? Id { get; set; } - /// Validated HTTPS consent URL. The runtime does not open it. - [JsonPropertyName("consentUrl")] - public required string ConsentUrl { get; set; } + /// Todo status. + [JsonPropertyName("status")] + public string? Status { get; set; } - /// Opaque ID accepted by continueConnection. - [JsonPropertyName("continuationId")] - public required string ContinuationId { get; set; } + /// Todo title. + [JsonPropertyName("title")] + public string? Title { get; set; } } -/// The service is still completing the connection without a consent URL. -/// The pending variant of . +/// Todo rows read from the session SQL database. Empty when no session database is available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ConnectorConnectResultPending : ConnectorConnectResult +public sealed class PlanReadSqlTodosResult { - /// - [JsonIgnore] - public override string Kind => "pending"; - - /// Opaque ID accepted by continueConnection. - [JsonPropertyName("continuationId")] - public required string ContinuationId { get; set; } + /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. + [JsonPropertyName("rows")] + public IList Rows { get => field ??= []; set; } } -/// Selects one Connector and the pinned host-owned account used for its service and MCP authorization. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorConnectRequest +internal sealed class SessionPlanReadSqlTodosRequest { - /// Opaque account selection ID. It must match the account already pinned to the session, if any. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; - - /// Canonical Connector name from the current catalog. - [JsonPropertyName("connectorName")] - public string ConnectorName { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Explicitly bounded continuation of a pending Connector connection. +/// A single dependency edge read from the session SQL `todo_deps` table, indicating that one todo must complete before another. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorContinueRequest +public sealed class PlanSqlTodoDependency { - /// Opaque continuation ID returned by connect, reconnect, or an earlier continuation. - [JsonPropertyName("continuationId")] - public string ContinuationId { get; set; } = string.Empty; - - /// Maximum wall-clock duration in milliseconds for this call. Must be between one and the capability limit. - [JsonPropertyName("deadlineMs")] - public int DeadlineMs { get; set; } + /// ID of the todo it depends on. + [JsonPropertyName("dependsOn")] + public string DependsOn { get; set; } = string.Empty; - /// Maximum catalog requests made by this call. Must be between one and the capability limit. - [JsonPropertyName("maxAttempts")] - public int MaxAttempts { get; set; } - - /// Delay in milliseconds between attempts. Must not exceed the capability limit. - [JsonPropertyName("pollIntervalMs")] - public int PollIntervalMs { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} - -/// Authoritative result after disconnect and MCP reconciliation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDisconnectResult -{ - /// Whether the service accepted the idempotent disconnect. - [JsonPropertyName("disconnected")] - public bool Disconnected { get; set; } - - /// Fresh authoritative session state after removing Connector-owned MCP servers. - [JsonPropertyName("status")] - public ConnectorStatus Status { get => field ??= new(); set; } -} - -/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorReconcileRequest -{ - /// Opaque account selection ID. It must match the account already pinned to the session, if any. - [JsonPropertyName("accountId")] - public required string AccountId { get; set; } - - /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. - [JsonPropertyName("forceConnectorName")] - public string? ForceConnectorName { get; set; } - - /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. - [JsonPropertyName("refreshCatalog")] - public bool? RefreshCatalog { get; set; } + /// ID of the todo that has the dependency. + [JsonPropertyName("todoId")] + public string TodoId { get; set; } = string.Empty; } -/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. +/// Todo rows + dependency edges read from the session SQL database. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorReconcileRequestWithSession +public sealed class PlanReadSqlTodosWithDependenciesResult { - /// Opaque account selection ID. It must match the account already pinned to the session, if any. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; - - /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. - [JsonPropertyName("forceConnectorName")] - public string? ForceConnectorName { get; set; } - - /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. - [JsonPropertyName("refreshCatalog")] - public bool? RefreshCatalog { get; set; } + /// Edges from the session SQL todo_deps table. Empty when no database, no todo_deps table, or the SELECT failed. Read independently from `rows`, so a broken todo_deps table does not affect the rows result and vice versa. + [JsonPropertyName("dependencies")] + public IList Dependencies { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. Empty when no database, no todos table, or the SELECT failed. + [JsonPropertyName("rows")] + public IList Rows { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsWithdrawProjectionRequest +internal sealed class SessionPlanReadSqlTodosWithDependenciesRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionManagedSettingsGetRequest +/// RPC data type for WorkspacesGetWorkspaceResultWorkspace operations. +public sealed class WorkspacesGetWorkspaceResultWorkspace { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Current Git branch. + [JsonPropertyName("branch")] + public string? Branch { get; set; } -/// Session plugin metadata, with name, marketplace, optional version, and enabled state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Plugin -{ - /// Opaque stable identity for a direct plugin source. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } + /// Whether the per-session Chronicle upgrade prompt was dismissed for the workspace. + [JsonPropertyName("chronicle_sync_dismissed")] + public bool? ChronicleSyncDismissed { get; set; } - /// Whether the plugin is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Name of the client that created the workspace. + [JsonPropertyName("client_name")] + public string? ClientName { get; set; } - /// Whether this managed desired plugin has an installed or live record. - [JsonPropertyName("installed")] - public bool? Installed { get; set; } + /// Timestamp when the workspace was created. + [JsonPropertyName("created_at")] + public DateTimeOffset? CreatedAt { get; set; } - /// Absolute marketplace directory for a live plugin. - [JsonPropertyName("installedFrom")] - public string? InstalledFrom { get; set; } + /// Current working directory associated with the workspace. + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Whether enterprise managed settings control this plugin. - [JsonPropertyName("managed")] - public bool? Managed { get; set; } + /// Git repository root associated with the workspace. + [JsonPropertyName("git_root")] + public string? GitRoot { get; set; } - /// Enabled state required by enterprise managed settings. - [JsonPropertyName("managedDesiredEnabled")] - public bool? ManagedDesiredEnabled { get; set; } + /// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration. + [JsonPropertyName("host_type")] + public WorkspacesWorkspaceDetailsHostType? HostType { get; set; } - /// Marketplace the plugin came from. - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; + /// Stable workspace identifier. + [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("id")] + public string Id { get; set; } = string.Empty; - /// Plugin name. + /// Most recent Mission Control event identifier observed for the workspace. + [JsonPropertyName("mc_last_event_id")] + public string? McLastEventId { get; set; } + + /// Mission Control session identifier associated with the workspace. + [JsonPropertyName("mc_session_id")] + public string? McSessionId { get; set; } + + /// Mission Control task identifier associated with the workspace. + [JsonPropertyName("mc_task_id")] + public string? McTaskId { get; set; } + + /// Workspace display name. [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + public string? Name { get; set; } - /// Runtime plugin provenance, such as "builtin". - [JsonPropertyName("source")] - public string? Source { get; set; } + /// Whether the workspace session can be steered remotely. + [JsonPropertyName("remote_steerable")] + public bool? RemoteSteerable { get; set; } - /// Installed version. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Repository identifier associated with the workspace. + [JsonPropertyName("repository")] + public string? Repository { get; set; } + + /// Number of persisted summaries in the workspace. + [JsonPropertyName("summary_count")] + public long? SummaryCount { get; set; } + + /// Timestamp when the workspace was last updated. + [JsonPropertyName("updated_at")] + public DateTimeOffset? UpdatedAt { get; set; } + + /// Whether the workspace name was explicitly chosen by the user. + [JsonPropertyName("user_named")] + public bool? UserNamed { get; set; } } -/// Plugins installed for the session, with their enabled state and version metadata. +/// Current workspace metadata for the session, including its absolute filesystem path when available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginList +public sealed class WorkspacesGetWorkspaceResult { - /// Installed plugins. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } + /// Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). + [JsonPropertyName("path")] + public string? Path { get; set; } + + /// Current workspace metadata, or null if not available. + [JsonPropertyName("workspace")] + public WorkspacesGetWorkspaceResultWorkspace? Workspace { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsListRequest +internal sealed class SessionWorkspacesGetWorkspaceRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Plugin source resolved relative to the session's authoritative working directory. +/// Workspace metadata fields to update. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsInstallRequest +internal sealed class WorkspacesUpdateMetadataRequest { + /// Opaque workspace context supplied by the session host. + [JsonPropertyName("context")] + public JsonElement? Context { get; set; } + + /// Optional workspace display name override. + [JsonPropertyName("name")] + public string? Name { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; } -/// Name (or spec) of the plugin to uninstall. +/// Optional session context used when creating a local workspace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUninstallRequestWithSession +internal sealed class WorkspacesEnsureRequest { - /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } - - /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Opaque workspace context supplied by the session host. + [JsonPropertyName("context")] + public JsonElement? Context { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Name (or spec) of the plugin to update. +/// Relative paths of files stored in the session workspace files directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUpdateRequestWithSession +public sealed class WorkspacesListFilesResult { - /// Plugin name or "plugin@marketplace" spec to update. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Slash-separated relative file paths in the workspace files directory. + [JsonPropertyName("files")] + public IList Files { get => field ??= []; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionWorkspacesListFilesRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Plugin names (or specs) to enable in the session's authoritative working directory. +/// Contents of the requested workspace file as a UTF-8 string. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsEnableRequest +public sealed class WorkspacesReadFileResult { - /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// File content as a UTF-8 string. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; +} + +/// Relative path of the workspace file to read. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesReadFileRequest +{ + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Plugin names (or specs) to disable in the session's authoritative working directory. +/// Relative path and UTF-8 content for the workspace file to create or overwrite. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsDisableRequest +internal sealed class WorkspacesCreateFileRequest { - /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// File content to write as a UTF-8 string. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// RPC data type for SessionPluginsReload operations. +/// Filesystem metadata for a path in the session workspace files directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPluginsReloadRequest +public sealed class WorkspacesStatFileResult { - /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. - [JsonPropertyName("deferRepoHooks")] - public bool? DeferRepoHooks { get; set; } + /// Creation time in Unix epoch milliseconds. + [JsonPropertyName("birthtimeMs")] + public double BirthtimeMs { get; set; } - /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadCustomAgents")] - public bool? ReloadCustomAgents { get; set; } + /// Whether the path identifies a directory. + [JsonPropertyName("isDirectory")] + public bool IsDirectory { get; set; } - /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). - [JsonPropertyName("reloadExtensions")] - public bool? ReloadExtensions { get; set; } + /// Whether the path identifies a regular file. + [JsonPropertyName("isFile")] + public bool IsFile { get; set; } - /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). - [JsonPropertyName("reloadHooks")] - public bool? ReloadHooks { get; set; } + /// Last modification time in Unix epoch milliseconds. + [JsonPropertyName("mtimeMs")] + public double MtimeMs { get; set; } - /// Reload MCP server connections after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadMcp")] - public bool? ReloadMcp { get; set; } + /// Size in bytes. + [JsonPropertyName("size")] + public double Size { get; set; } } -/// RPC data type for SessionPluginsReloadRequestWithSession operations. +/// Relative path of the workspace file or directory to inspect. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsReloadRequestWithSession +internal sealed class WorkspacesStatFileRequest { - /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. - [JsonPropertyName("deferRepoHooks")] - public bool? DeferRepoHooks { get; set; } - - /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadCustomAgents")] - public bool? ReloadCustomAgents { get; set; } + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). - [JsonPropertyName("reloadExtensions")] - public bool? ReloadExtensions { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). - [JsonPropertyName("reloadHooks")] - public bool? ReloadHooks { get; set; } +/// Directory to create within the session workspace files directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesCreateDirectoryRequest +{ + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Reload MCP server connections after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadMcp")] - public bool? ReloadMcp { get; set; } + /// Whether to create missing parent directories. Defaults to false. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// File or directory to remove from the session workspace files directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsMarketplacesListRequest +internal sealed class WorkspacesRemovePathRequest { + /// Whether a missing path should be treated as success. Defaults to false. + [JsonPropertyName("force")] + public bool? Force { get; set; } + + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Whether to remove directory contents recursively. Defaults to false. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Marketplace source and optional working directory for relative-path resolution. +/// Source and destination paths for a rename within the session workspace files directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesAddRequestWithSession +internal sealed class WorkspacesRenamePathRequest { + /// Slash-separated destination path relative to the workspace files directory. + [JsonPropertyName("destination")] + public string Destination { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. + /// Slash-separated source path relative to the workspace files directory. [JsonPropertyName("source")] public string Source { get; set; } = string.Empty; - - /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } } -/// Name of the marketplace to remove and an optional force flag. +/// Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint filename. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesRemoveRequestWithSession +public sealed class WorkspacesCheckpoints { - /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// Filename of the checkpoint within the workspace checkpoints directory. + [JsonPropertyName("filename")] + public string Filename { get; set; } = string.Empty; - /// Marketplace name to remove. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Checkpoint number assigned by the workspace manager. + [JsonPropertyName("number")] + public long Number { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Human-readable checkpoint title. + [JsonPropertyName("title")] + public string Title { get; set; } = string.Empty; } -/// Name of the marketplace whose plugin catalog to fetch. +/// Workspace checkpoints in chronological order; empty when the workspace is not enabled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesBrowseRequestWithSession +public sealed class WorkspacesListCheckpointsResult { - /// Marketplace name to browse. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Workspace checkpoints in chronological order. Empty when workspace is not enabled. + [JsonPropertyName("checkpoints")] + public IList Checkpoints { get => field ??= []; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionWorkspacesListCheckpointsRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// RPC data type for SessionPluginsMarketplacesRefresh operations. +/// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPluginsMarketplacesRefreshRequest +public sealed class WorkspacesReadCheckpointResult { - /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. + [JsonPropertyName("content")] + public string? Content { get; set; } } -/// RPC data type for SessionPluginsMarketplacesRefreshRequestWithSession operations. +/// Checkpoint number to read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsMarketplacesRefreshRequestWithSession +internal sealed class WorkspacesReadCheckpointRequest { - /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Checkpoint number to read. + [JsonPropertyName("number")] + public long Number { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. +/// Persisted summary metadata and refreshed workspace metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderSessionToken +public sealed class WorkspacesAddSummaryResult { - /// When the token expires, if known. Callers should refresh by calling `getEndpoint` again before this time, or reactively on any 401/403 response from `baseUrl`. - [JsonPropertyName("expiresAt")] - public DateTimeOffset? ExpiresAt { get; set; } - - /// HTTP header name the token must be sent under. - [JsonPropertyName("header")] - public string Header { get; set; } = string.Empty; - - /// The model the token is bound to, when applicable. When set, the token is only valid for requests against this model. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Metadata for the persisted summary. + [JsonPropertyName("summary")] + public IDictionary? Summary { get; set; } - /// The short-lived token value. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// Refreshed metadata for the containing workspace. + [JsonPropertyName("workspace")] + public IDictionary? Workspace { get; set; } } -/// A snapshot of the provider endpoint the session is currently configured to talk to. +/// Compaction summary checkpoint to persist. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderEndpoint +internal sealed class WorkspacesAddSummaryRequest { - /// A credential the caller should use with this endpoint. Omitted only when the endpoint accepts unauthenticated requests. - [JsonPropertyName("apiKey")] - public string? ApiKey { get; set; } - - /// Base URL to pass to the LLM client library. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("baseUrl")] - public string BaseUrl { get; set; } = string.Empty; - - /// HTTP headers the caller must include on every outbound request. - [JsonPropertyName("headers")] - public IDictionary Headers { get => field ??= new Dictionary(); set; } + /// Markdown summary content to persist. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. - [JsonPropertyName("sessionToken")] - public ProviderSessionToken? SessionToken { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Transport to be used for provider requests. - [JsonPropertyName("transport")] - public ProviderEndpointTransport? Transport { get; set; } + /// Summary title shown in checkpoint listings. + [JsonPropertyName("title")] + public string Title { get; set; } = string.Empty; +} - /// Provider family. Matches the `type` field of a BYOK provider config. - [JsonPropertyName("type")] - public ProviderEndpointType Type { get; set; } +/// Rollback point for local workspace summaries. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesTruncateSummariesRequest +{ + /// Number of newest summaries to keep. + [JsonPropertyName("keepCount")] + public long KeepCount { get; set; } - /// Wire API to be used, when required for the provider type. - [JsonPropertyName("wireApi")] - public ProviderEndpointWireApi? WireApi { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// RPC data type for SessionProviderGetEndpoint operations. +/// Autopilot objective file content, or null when missing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionProviderGetEndpointRequest +public sealed class WorkspacesReadAutopilotObjectiveResult { - /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Autopilot objective file content, or null when missing. + [JsonPropertyName("content")] + public string? Content { get; set; } } -/// RPC data type for SessionProviderGetEndpointRequestWithSession operations. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionProviderGetEndpointRequestWithSession +internal sealed class SessionWorkspacesReadAutopilotObjectiveRequest { - /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The selectable model entries synthesized for the models added by this call. +/// Result of writing the autopilot objective file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderAddResult +public sealed class WorkspacesWriteAutopilotObjectiveResult { - /// Synthesized selectable model entries for the newly added BYOK models, each under its provider-qualified selection id (`provider/id`). Empty when only providers were added. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// Filesystem operation performed. + [JsonPropertyName("operation")] + public string Operation { get; set; } = string.Empty; } -/// BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both. +/// Autopilot objective file content to persist. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ProviderAddRequest +internal sealed class WorkspacesWriteAutopilotObjectiveRequest { - /// BYOK model definitions to register. Each must reference a provider that is already registered or included in this same call. Selection ids (`provider/id`) must be unique across the registry. - [JsonPropertyName("models")] - public IList? Models { get; set; } - - /// Named BYOK provider connections to register, additive to any providers already in the registry. Each name must be unique across the registry and must not contain '/'. - [JsonPropertyName("providers")] - public IList? Providers { get; set; } + /// Autopilot objective file content. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The selectable model entries and selection ids synthesized for the synchronized BYOK models. +/// Result of deleting the autopilot objective file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderSyncResult +public sealed class WorkspacesDeleteAutopilotObjectiveResult { - /// True when synchronization withdrew the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Synchronization never promotes a surviving host model in its place: publishing a model offers it, and the choice of which model to use stays with the user. - [JsonPropertyName("modelDeselected")] - public bool? ModelDeselected { get; set; } - - /// Synthesized selectable model entries for the synchronized BYOK models. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } - - /// Provider-qualified model selection ids present after synchronization. - [JsonPropertyName("selectionIds")] - public IList SelectionIds { get => field ??= []; set; } + /// True when a file was deleted. + [JsonPropertyName("deleted")] + public bool Deleted { get; set; } } -/// Authoritative BYOK provider and model registry snapshot to apply atomically to the session. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ProviderSyncRequest +internal sealed class SessionWorkspacesDeleteAutopilotObjectiveRequest { - /// BYOK model definition snapshot. Models absent from this list are removed. - [JsonPropertyName("models")] - public IList? Models { get; set; } - - /// Named BYOK provider connection snapshot. Providers absent from this list are removed. - [JsonPropertyName("providers")] - public IList? Providers { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// What the withdrawal actually removed from the registry. +/// Whether the autopilot objective file exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderWithdrawResult +public sealed class WorkspacesAutopilotObjectiveExistsResult { - /// True when withdrawal removed the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Withdrawal never promotes a surviving model in its place: the choice of which model to use stays with the user. - [JsonPropertyName("modelDeselected")] - public bool? ModelDeselected { get; set; } - - /// Providers removed because one of the withdrawn models was the last entry referencing them. A provider that merely has no models is not removed. - [JsonPropertyName("providersRemoved")] - public IList ProvidersRemoved { get => field ??= []; set; } - - /// Selection ids that were registered and are now withdrawn. Excludes requested ids that were not present. - [JsonPropertyName("withdrawn")] - public IList Withdrawn { get => field ??= []; set; } + /// True when the objective file exists. + [JsonPropertyName("exists")] + public bool Exists { get; set; } } -/// Host-managed model selection ids to withdraw from the session's BYOK registry. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ProviderWithdrawRequest +internal sealed class SessionWorkspacesAutopilotObjectiveExistsRequest { - /// Provider-qualified selection ids to withdraw. Ids that are not registered are ignored, so withdrawal is idempotent. A provider left with no models referencing it is removed too. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the session options patch was applied successfully. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionUpdateOptionsResult +/// RPC data type for WorkspacesSaveLargePasteResultSaved operations. +public sealed class WorkspacesSaveLargePasteResultSaved { - /// Number of hooks loaded from installed plugins, returned when installedPlugins is updated. - [JsonPropertyName("pluginHookCount")] - public long? PluginHookCount { get; set; } + /// Filename within the workspace files directory. + [JsonPropertyName("filename")] + public string Filename { get; set; } = string.Empty; - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Absolute filesystem path to the saved paste file. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; + + /// Size of the saved file in bytes. + [JsonPropertyName("sizeBytes")] + public long SizeBytes { get; set; } } -/// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. +/// Descriptor for the saved paste file, or null when the workspace is unavailable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OptionsUpdateAdditionalContentExclusionPolicyRuleSource +public sealed class WorkspacesSaveLargePasteResult { - /// Name of the policy source. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Type of the policy source. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; + /// Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions). + [JsonPropertyName("saved")] + public WorkspacesSaveLargePasteResultSaved? Saved { get; set; } } -/// Single content-exclusion rule supplied to `session.options.update`, with paths, match conditions, and source. +/// Pasted content to save as a UTF-8 file in the session workspace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OptionsUpdateAdditionalContentExclusionPolicyRule +internal sealed class WorkspacesSaveLargePasteRequest { - /// Conditions of which at least one must match. - [JsonPropertyName("ifAnyMatch")] - public IList? IfAnyMatch { get; set; } - - /// Conditions none of which may match. - [JsonPropertyName("ifNoneMatch")] - public IList? IfNoneMatch { get; set; } - - /// Path patterns covered by this rule. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// Pasted content to save as a UTF-8 file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. - [JsonPropertyName("source")] - public OptionsUpdateAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Content-exclusion policy supplied to `session.options.update`, with rules, last-updated data, and scope. +/// Complete text used to generate one session diff. These are display contents, with the same text decoding as the patch, not a file-restore contract. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OptionsUpdateAdditionalContentExclusionPolicy +public sealed class WorkspaceDiffContents { - /// Opaque policy update timestamp supplied by the host. - [JsonPropertyName("last_updated_at")] - public JsonElement LastUpdatedAt { get; set; } - - /// Content-exclusion rules to apply. - [JsonPropertyName("rules")] - public IList Rules { get => field ??= []; set; } + /// Complete current text read when computing the diff. Omitted for a deleted file; an empty string represents an existing empty file. + [JsonPropertyName("after")] + public string? After { get; set; } - /// Allowed values for the `OptionsUpdateAdditionalContentExclusionPolicyScope` enumeration. - [JsonPropertyName("scope")] - public OptionsUpdateAdditionalContentExclusionPolicyScope Scope { get; set; } + /// Complete text before the session first changed the file. Omitted when the file did not exist; an empty string represents an existing empty file. + [JsonPropertyName("before")] + public string? Before { get; set; } } -/// Options scoped to the built-in CAPI (Copilot API) provider. +/// A single changed file and its unified diff. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CapiSessionOptions +public sealed class WorkspaceDiffFileChange { - /// Routing preference for sessions whose model is `auto`. On create or cold resume, this establishes the preference sent as `tier` on CAPI `/auto` requests; when omitted on cold resume, the runtime restores the last committed preference. On resident resume, a different value requests a safe switch after resume succeeds and cannot change an in-flight turn. Successful switches are persisted for later cold resume. When no preference is supplied or restored, CAPI default routing is used. `fast` is an integrator-only latency preset, not a first-party GitHub Copilot product preference. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } + /// Type of change represented by this file diff. + [JsonPropertyName("changeType")] + public WorkspaceDiffFileChangeType ChangeType { get; set; } - /// Whether to use WebSocket transport for the CAPI Responses API. Enabled by default when the model advertises `ws:/responses` support; set to `false` to force the HTTP Responses transport in environments where WebSockets are blocked (e.g. behind a proxy). Setting this to `false` is equivalent to the `COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES` environment variable. - [JsonPropertyName("enableWebSocketResponses")] - public bool? EnableWebSocketResponses { get; set; } + /// Full text used for this patch, only when includeContents was requested for session mode. Omitted for binary, oversized or unavailable contents, and for fallback results. Read isFallback and isTruncated before treating an absent value as a missing file. + [JsonPropertyName("contents")] + public WorkspaceDiffContents? Contents { get; set; } + + /// Unified diff content for the file. Empty when the diff was truncated. + [JsonPropertyName("diff")] + public string Diff { get; set; } = string.Empty; + + /// Whether the diff content was omitted because it exceeded the per-file size limit. + [JsonPropertyName("isTruncated")] + public bool? IsTruncated { get; set; } + + /// Original file path for renamed files. + [JsonPropertyName("oldPath")] + public string? OldPath { get; set; } + + /// Path to the changed file, relative to the workspace root when the file lives under it. A file changed outside the workspace root keeps a `../`-relative path, or an absolute path when no relative path exists (for example a different Windows drive). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Installed plugin record for a session, with marketplace, version, install time, enabled state, cache path, and source. +/// Workspace diff result for the requested mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionInstalledPlugin +public sealed class WorkspaceDiffResult { - /// Path where the plugin is cached locally. - [JsonPropertyName("cache_path")] - public string? CachePath { get; set; } + /// Default branch used for a branch diff, when branch mode was requested. + [JsonPropertyName("baseBranch")] + public string? BaseBranch { get; set; } - /// Whether the plugin is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Changed files and their unified diffs. + [JsonPropertyName("changes")] + public IList Changes { get => field ??= []; set; } - /// Installation timestamp (ISO-8601). - [JsonPropertyName("installed_at")] - public string InstalledAt { get; set; } = string.Empty; + /// Whether the requested diff fell back to unstaged changes, either because branch diff failed or session diff was unavailable. + [JsonPropertyName("isFallback")] + public bool IsFallback { get; set; } - /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. - [JsonPropertyName("installed_from")] - public string? InstalledFrom { get; set; } + /// Effective mode used for the returned changes. + [JsonPropertyName("mode")] + public WorkspaceDiffMode Mode { get; set; } - /// Marketplace the plugin came from (empty string for direct repo installs). - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; + /// Diff mode requested by the client. + [JsonPropertyName("requestedMode")] + public WorkspaceDiffMode RequestedMode { get; set; } - /// Plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Why the session diff could not be produced, when applicable. Set only when `session` mode was requested and `isFallback` is true, so a client can tell the permanent `file-change-tracking-disabled` apart from the transient `session-busy`, which the same request answers once the session settles. Never set for `unstaged` or `branch` mode, and never `unsupported-remote-session`: a remote session's captures live on its own host, so a `session`-mode diff is rejected for one rather than answered with a controller-side fallback. + [JsonPropertyName("unavailableReason")] + public HistoryRewindUnavailableReason? UnavailableReason { get; set; } +} - /// Source descriptor for direct repo installs (when marketplace is empty). - [JsonPropertyName("source")] - public JsonElement? Source { get; set; } +/// Parameters for computing a workspace diff. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesDiffRequest +{ + /// When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + [JsonPropertyName("ignoreWhitespace")] + public bool? IgnoreWhitespace { get; set; } - /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. - [JsonPropertyName("source_sha")] - public string? SourceSha { get; set; } + /// Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + [JsonPropertyName("includeContents")] + public bool? IncludeContents { get; set; } - /// Installed version, if known. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Diff mode requested by the client. + [JsonPropertyName("mode")] + public required WorkspaceDiffMode Mode { get; set; } } -/// Custom model-provider configuration (BYOK). +/// Parameters for computing a workspace diff. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderConfig +internal sealed class WorkspacesDiffRequestWithSession { - /// API key. Optional for local providers like Ollama. - [JsonPropertyName("apiKey")] - public string? ApiKey { get; set; } - - /// Azure-specific provider options. - [JsonPropertyName("azure")] - public ProviderConfigAzure? Azure { get; set; } - - /// API endpoint URL. - [JsonPropertyName("baseUrl")] - public string BaseUrl { get; set; } = string.Empty; + /// When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + [JsonPropertyName("ignoreWhitespace")] + public bool? IgnoreWhitespace { get; set; } - /// Bearer token for authentication. Sets the Authorization header directly. Takes precedence over apiKey when both are set. - [JsonPropertyName("bearerToken")] - public string? BearerToken { get; set; } + /// Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + [JsonPropertyName("includeContents")] + public bool? IncludeContents { get; set; } - /// When true, the SDK client supplies bearer tokens on demand: the runtime calls the client-session `providerToken.getToken` callback before each request and applies the returned token as an `Authorization: Bearer <token>` header. This is the bearer/OAuth scheme used by Azure AD / managed-identity tokens and provider OAuth access tokens (including Anthropic's), not a provider-specific API-key header such as Anthropic's `x-api-key`. The token-acquiring function itself stays on the SDK side and is never serialized; only this flag crosses the wire. When set alongside `apiKey`/`bearerToken`, the callback takes precedence: the runtime applies the token returned by `providerToken.getToken` as the `Authorization: Bearer` header for each request and does not send the static credential. - [JsonPropertyName("hasBearerTokenProvider")] - public bool? HasBearerTokenProvider { get; set; } + /// Diff mode requested by the client. + [JsonPropertyName("mode")] + public WorkspaceDiffMode Mode { get; set; } - /// Custom HTTP headers to include in all outbound requests to the provider. - [JsonPropertyName("headers")] - public IDictionary? Headers { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Maximum context window tokens for the model. - [JsonPropertyName("maxContextWindowTokens")] - public double? MaxContextWindowTokens { get; set; } +/// Current per-window credit limit and consumption for an autopilot objective. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AutopilotObjectiveCreditLimit +{ + /// Configured AI-credit cap, when one is set. + [JsonPropertyName("credits")] + public double? Credits { get; set; } - /// Maximum output tokens for the model. - [JsonPropertyName("maxOutputTokens")] - public double? MaxOutputTokens { get; set; } + /// Window consumption in fractional AI credits, for display. + [JsonPropertyName("creditsUsed")] + public double CreditsUsed { get; set; } - /// Maximum prompt/input tokens for the model. - [JsonPropertyName("maxPromptTokens")] - public double? MaxPromptTokens { get; set; } + /// Exact window consumption in non-negative integer nano-AIU, encoded as a decimal string. + [RegularExpression("^[0-9]+$")] + [JsonPropertyName("creditsUsedNanoAiu")] + public string CreditsUsedNanoAiu { get; set; } = string.Empty; +} - /// Overrides for model capabilities when they cannot be inferred from modelId. - [JsonPropertyName("modelCapabilities")] - public ModelCapabilitiesOverride? ModelCapabilities { get; set; } +/// Public, persistence-independent projection of an autopilot objective. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AutopilotObjectiveState +{ + /// Optional summary recorded when the objective completed. + [JsonPropertyName("completionSummary")] + public string? CompletionSummary { get; set; } - /// Well-known model ID used for capability lookup. When set, agent behavior config and token limits are inferred from this model. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Exact lifetime AI-credit consumption in non-negative integer nano-AIU, encoded as a decimal string. + [RegularExpression("^[0-9]+$")] + [JsonPropertyName("creditCountNanoAiu")] + public string CreditCountNanoAiu { get; set; } = string.Empty; - /// The product serving the model, reported in telemetry as `model_provider`. Set it when `type` alone cannot identify the product, such as Ollama or LM Studio behind an OpenAI-compatible endpoint. Only affects telemetry. - [JsonPropertyName("modelProvider")] - public ProviderConfigModelProvider? ModelProvider { get; set; } + /// Current per-window consumption and optional cap, when a credit-tracking window is present. + [JsonPropertyName("creditLimit")] + public AutopilotObjectiveCreditLimit? CreditLimit { get; set; } - /// Provider name used for model and telemetry attribution. - [JsonPropertyName("providerName")] - public string? ProviderName { get; set; } + /// Session-local objective identifier. + [JsonPropertyName("id")] + public long Id { get; set; } - /// Provider transport. Defaults to "http". - [JsonPropertyName("transport")] - public ProviderConfigTransport? Transport { get; set; } + /// User-provided objective text. + [JsonPropertyName("objective")] + public string Objective { get; set; } = string.Empty; - /// Provider type. Defaults to "openai" for generic OpenAI-compatible APIs. - [JsonPropertyName("type")] - public ProviderConfigType? Type { get; set; } + /// Optional reason the objective is paused. + [JsonPropertyName("pauseReason")] + public string? PauseReason { get; set; } - /// Wire API format (openai/azure only). Defaults to "completions". - [JsonPropertyName("wireApi")] - public ProviderConfigWireApi? WireApi { get; set; } + /// Current normalized lifecycle status. + [JsonPropertyName("status")] + public AutopilotObjectiveStatus Status { get; set; } - /// The model identifier sent to the provider API for inference (the "wire" model), as opposed to modelId which is the well-known base. - [JsonPropertyName("wireModel")] - public string? WireModel { get; set; } + /// Number of objective turns started. + [JsonPropertyName("turnCount")] + public long TurnCount { get; set; } } -/// -/// Command-scoped GitHub credential injection for the shell commands an agent runs. -/// -/// Each channel is opt-in and independent, and injection is scoped to the individual command -/// spawn: the credential is resolved from the session's *current* authentication at every spawn -/// and reaches only spawns whose script actually invokes `git` or `gh`. Because nothing is -/// retained between spawns, replacing the session credential (`session.gitHubAuth.setCredentials`) -/// changes what the next spawned command presents — which seeding a credential into the runtime -/// process's own environment cannot do, since a child's environment is fixed at `exec`. -/// -/// The credential is matched to the host it authenticates to, so a github.com credential is never -/// presented to a GitHub Enterprise host and vice versa. Where a channel cannot express that -/// boundary it injects nothing rather than crossing it -- see `gh` below. -/// -/// This is independent of `sandboxConfig`: it is a decision about which identity the agent -/// presents, not about what the agent may touch, and it works on every platform whether or not -/// an OS sandboxing backend is available. `sandboxConfig.auth` remains the sandbox-scoped -/// spelling and is additive with this one. -/// +/// Canonical runtime state for the session's current autopilot objective. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellCredentials +public sealed class AutopilotObjectiveGetStateResult { - /// - /// Whether to authenticate the agent's `gh` commands as the session's GitHub credential, by - /// exporting `GH_TOKEN` to a spawn that runs `gh`. Any inherited `gh` credential is removed from - /// spawns that do not, so the credential stays command-scoped. - /// - /// Applies to a github.com credential only. `gh` picks its credential variable from the host a - /// command targets rather than the one the credential belongs to, and the command can choose that - /// target, so `GH_ENTERPRISE_TOKEN` would offer a single-tenant enterprise credential to every - /// other enterprise host. A session whose credential is enterprise-scoped therefore runs `gh` - /// unauthenticated; its `git` commands are unaffected, because `http.<host>.extraheader` is scoped - /// to one host by construction. Default: false (opt-in). - /// - [JsonPropertyName("gh")] - public bool? Gh { get; set; } + /// Current objective state, or `null` when the session has no objective. + [JsonPropertyName("state")] + public AutopilotObjectiveState? State { get; set; } +} - /// - /// Whether to authenticate the agent's `git` commands as the session's GitHub credential, by - /// injecting an `http.<host>.extraheader` (plus `insteadOf` rewrites so SSH-spelled remotes for - /// that host use the authenticated HTTPS transport). Applied only to a spawn that runs a - /// remote-contacting `git` subcommand. Default: false (opt-in). - /// - [JsonPropertyName("git")] - public bool? Git { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionAutopilotObjectiveGetStateRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A host-provided script sourced before each built-in shell command when its shell target matches the active shell. +/// Characters that, when typed in the composer, should trigger a `completions.request`. Empty when the session has no host-driven completions (e.g. local sessions, or a relay host that does not advertise `completionTriggerCharacters`). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellInitScript +public sealed class CompletionsGetTriggerCharactersResult { - /// Path to the script to source. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Trigger characters advertised by the host (e.g. `["@", "#"]`). Empty disables host-driven completions for the session. + [JsonPropertyName("triggerCharacters")] + public IList TriggerCharacters { get => field ??= []; set; } +} - /// Built-in shell that may source this script. - [JsonPropertyName("shell")] - public ShellInitScriptShell Shell { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionCompletionsGetTriggerCharactersRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Per-session settings for built-in shell tools. +/// A single host-driven completion. Accepting an item replaces `[rangeStart, rangeEnd)` (UTF-16 code units) in the composer with `insertText`; when the range is absent, the active token around the cursor is replaced. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellOptions +public sealed class SessionCompletionItem { - /// Command-scoped GitHub credential injection for shell commands. - [JsonPropertyName("credentials")] - public ShellCredentials? Credentials { get; set; } + /// Text spliced into the composer when the item is accepted. + [JsonPropertyName("insertText")] + public string InsertText { get; set; } = string.Empty; - /// Controls automatic non-interactive profile loading where supported. Explicit initScripts are unaffected. - [JsonPropertyName("initProfile")] - public ShellInitProfile? InitProfile { get; set; } + /// Render-kind hint for the picker row (e.g. `"document"`, `"directory"`), derived from the host's display kind. + [JsonPropertyName("kind")] + public string? Kind { get; set; } - /// - /// Ordered host-provided script paths sourced before each built-in shell command when the - /// entry's shell target matches the active shell. Use these for rc files, environment setup scripts, - /// or other custom scripts. A script that returns a nonzero status is reported, and later scripts - /// and the user command continue while the shell remains running. Because scripts are sourced into - /// the command shell, `exit`, `exec`, failures under `set -e`, or other shell-terminating behavior - /// can prevent continuation. Script standard output is preserved; Bash script stderr is discarded, - /// PowerShell exception messages are replaced, and runtime-generated failure notices omit - /// configured script paths. When sandboxing is enabled, each script must already be readable under - /// the active sandbox filesystem policy. Pass an empty array to clear the list. - /// - [JsonPropertyName("initScripts")] - public IList? InitScripts { get; set; } + /// Primary display label for the picker row. Falls back to `insertText` when absent. + [JsonPropertyName("label")] + public string? Label { get; set; } - /// - /// Flags passed to the active built-in shell process on startup, replacing its default flags. - /// When omitted, the built-in Bash shell uses `--norc --noprofile`, - /// and the built-in PowerShell shell uses `-NoProfile -NoLogo`. - /// - [JsonPropertyName("processFlags")] - public IList? ProcessFlags { get; set; } + /// End (exclusive) of the replacement range in `text`, in UTF-16 code units. + [JsonPropertyName("rangeEnd")] + public long? RangeEnd { get; set; } + + /// Start of the replacement range in `text`, in UTF-16 code units. + [JsonPropertyName("rangeStart")] + public long? RangeStart { get; set; } } -/// Patch of mutable session options to apply to the running session. +/// Host-driven completion items for the current composer input. Empty when the host returns no items or does not support completions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionUpdateOptionsParams +public sealed class CompletionsRequestResult { - /// Additional content-exclusion policies to merge into the session's policy set. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("additionalContentExclusionPolicies")] - public IList? AdditionalContentExclusionPolicies { get; set; } - - /// Runtime context discriminator (e.g., `cli`, `actions`). - [JsonPropertyName("agentContext")] - public string? AgentContext { get; set; } - - /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. - [JsonPropertyName("allowAllMcpServerInstructions")] - public bool? AllowAllMcpServerInstructions { get; set; } + /// Completion items in host-ranked order. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } +} - /// Whether to disable the `ask_user` tool (encourages autonomous behavior). - [JsonPropertyName("askUserDisabled")] - public bool? AskUserDisabled { get; set; } +/// Request host-driven completions for the current composer input. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class CompletionsRequestRequest +{ + /// Cursor offset within `text`, in UTF-16 code units. + [JsonPropertyName("offset")] + public long Offset { get; set; } - /// Allowlist of tool names available to this session. - [JsonPropertyName("availableTools")] - public IList? AvailableTools { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Options scoped to the built-in CAPI (Copilot API) provider. - [JsonPropertyName("capi")] - public CapiSessionOptions? Capi { get; set; } + /// The full composed composer input. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; +} - /// Identifier of the client driving the session. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } +/// Instruction sources loaded for the session, in merge order. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class InstructionsGetSourcesResult +{ + /// Instruction sources for the session. + [JsonPropertyName("sources")] + public IList Sources { get => field ??= []; set; } +} - /// Whether to include the `Co-authored-by` trailer in commit messages. - [JsonPropertyName("coauthorEnabled")] - public bool? CoauthorEnabled { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionInstructionsGetSourcesRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. - [JsonPropertyName("contextTier")] - public OptionsUpdateContextTier? ContextTier { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionInstructionsReloadRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether to allow auto-mode continuation across turns. - [JsonPropertyName("continueOnAutoMode")] - public bool? ContinueOnAutoMode { get; set; } +/// Result of one customization reload component. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CustomizationReloadOutcome +{ + /// Reason for a skipped component or description of a failure, when available. + [JsonPropertyName("detail")] + public string? Detail { get; set; } - /// Override URL for the Copilot API endpoint. - [JsonPropertyName("copilotUrl")] - public string? CopilotUrl { get; set; } + /// Whether the component reloaded, was skipped, or failed. + [JsonPropertyName("status")] + public CustomizationReloadStatus Status { get; set; } - /// Whether to default custom agents to local-only execution. - [JsonPropertyName("customAgentsLocalOnly")] - public bool? CustomAgentsLocalOnly { get; set; } + /// Component whose reload was attempted or skipped. + [JsonPropertyName("subsystem")] + public CustomizationReloadSubsystem Subsystem { get; set; } +} - /// Instruction source IDs to exclude from the system prompt. - [JsonPropertyName("disabledInstructionSources")] - public IList? DisabledInstructionSources { get; set; } +/// Results of reloading discovered session customizations. Inspect outcomes for reloaded, skipped, or failed subsystems; a rejection may follow partial mutation. Changes to the model-facing prompt and tools apply on the next turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CustomizationsReloadResult +{ + /// Errors from any component that could not be refreshed. + [JsonPropertyName("errors")] + public IList Errors { get => field ??= []; set; } - /// Skill IDs that should be excluded from this session. - [JsonPropertyName("disabledSkills")] - public IList? DisabledSkills { get; set; } + /// Outcome of each component in reload order; a skipped component was not configured or loaded. + [JsonPropertyName("outcomes")] + public IList Outcomes { get => field ??= []; set; } - /// Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. - [JsonPropertyName("enableFileHooks")] - public bool? EnableFileHooks { get; set; } + /// Warnings from skill discovery. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } +} - /// Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). - [JsonPropertyName("enableHostGitOperations")] - public bool? EnableHostGitOperations { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionCustomizationsReloadRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions`. - [JsonPropertyName("enableOnDemandInstructionDiscovery")] - public bool? EnableOnDemandInstructionDiscovery { get; set; } +/// Indicates whether fleet mode was successfully activated. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class FleetStartResult +{ + /// Whether fleet mode was successfully activated. + [JsonPropertyName("started")] + public bool Started { get; set; } +} - /// Whether to surface reasoning-summary events from the model. - [JsonPropertyName("enableReasoningSummaries")] - public bool? EnableReasoningSummaries { get; set; } +/// Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FleetStartRequest +{ + /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the fleet request. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } - /// Whether shell-script safety heuristics are enabled. - [JsonPropertyName("enableScriptSafety")] - public bool? EnableScriptSafety { get; set; } + /// If false, this request will not trigger a Premium Request Unit charge. User requests default to billable. + [JsonInclude] + [JsonPropertyName("billable")] + internal bool? Billable { get; set; } - /// Whether to enable cross-session store writes and reads. - [JsonPropertyName("enableSessionStore")] - public bool? EnableSessionStore { get; set; } + /// Optional user prompt to combine with fleet instructions. + [JsonPropertyName("prompt")] + public string? Prompt { get; set; } - /// Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. - [JsonPropertyName("enableSkills")] - public bool? EnableSkills { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Whether to stream model responses. - [JsonPropertyName("enableStreaming")] - public bool? EnableStreaming { get; set; } + /// If true, await completion of the agentic loop for this fleet request before returning. Defaults to false. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } +} - /// How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). - [JsonPropertyName("envValueMode")] - public OptionsUpdateEnvValueMode? EnvValueMode { get; set; } +/// Agents available to the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentList +{ + /// Available agents. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } +} - /// Override directory for the session-events log. When unset, the runtime's default events log directory is used. - [JsonPropertyName("eventsLogDirectory")] - public string? EventsLogDirectory { get; set; } +/// RPC data type for SessionAgentList operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionAgentListRequest +{ + /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. + [JsonPropertyName("includeBuiltInAgents")] + public bool? IncludeBuiltInAgents { get; set; } - /// Whether subagent callback events should be forwarded into the session event log sink. - [JsonPropertyName("eventsLogIncludesSubagents")] - public bool? EventsLogIncludesSubagents { get; set; } + /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. + [JsonPropertyName("includePrompt")] + public bool? IncludePrompt { get; set; } +} - /// Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. - [JsonPropertyName("excludedBuiltinAgents")] - public IList? ExcludedBuiltinAgents { get; set; } +/// RPC data type for SessionAgentListRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionAgentListRequestWithSession +{ + /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. + [JsonPropertyName("includeBuiltInAgents")] + public bool? IncludeBuiltInAgents { get; set; } - /// Denylist of tool names for this session. - [JsonPropertyName("excludedTools")] - public IList? ExcludedTools { get; set; } + /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. + [JsonPropertyName("includePrompt")] + public bool? IncludePrompt { get; set; } - /// Map of feature-flag IDs to their boolean enabled state. - [JsonPropertyName("featureFlags")] - public IDictionary? FeatureFlags { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. - [JsonPropertyName("ignoredSkillsLocations")] - public IList? IgnoredSkillsLocations { get; set; } +/// An in-memory authored prompt override for an available agent. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentSetPromptRequest +{ + /// Stable effective agent id. Plugin namespace separators are normalized. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. Set to null to remove the allowlist restriction. - [JsonPropertyName("includedBuiltinAgents")] - public IList? IncludedBuiltinAgents { get; set; } + /// Replacement authored prompt. Empty text is valid. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. - [JsonPropertyName("includedBuiltinSkills")] - public IList? IncludedBuiltinSkills { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. - [JsonPropertyName("installedPlugins")] - public IList? InstalledPlugins { get; set; } +/// The currently selected custom agent, or null when using the default agent. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentGetCurrentResult +{ + /// Currently selected custom agent, or null if using the default agent. + [JsonPropertyName("agent")] + public AgentInfo? Agent { get; set; } +} - /// Stable integration identifier used for analytics and rate-limit attribution. - [JsonPropertyName("integrationId")] - public string? IntegrationId { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionAgentGetCurrentRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether experimental capabilities are enabled. - [JsonPropertyName("isExperimentalMode")] - public bool? IsExperimentalMode { get; set; } +/// The newly selected custom agent. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentSelectResult +{ + /// The newly selected custom agent. + [JsonPropertyName("agent")] + public AgentInfo Agent { get => field ??= new(); set; } +} - /// Whether interactive shell sessions are logged. - [JsonPropertyName("logInteractiveShells")] - public bool? LogInteractiveShells { get; set; } +/// Name of the custom agent to select for subsequent turns. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentSelectRequest +{ + /// Name of the custom agent to select. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Identifier sent to LSP-style integrations. - [JsonPropertyName("lspClientName")] - public string? LspClientName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). - [JsonPropertyName("manageScheduleEnabled")] - public bool? ManageScheduleEnabled { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionAgentDeselectRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Maximum decoded byte size of a single model-facing binary tool result (e.g. an image) persisted inline in session events and re-presented to the model on later turns / resume. Larger results are persisted as a metadata-only marker and shown to the model as a short text note. Defaults to 10 MB. - [JsonPropertyName("maxInlineBinaryBytes")] - public long? MaxInlineBinaryBytes { get; set; } +/// Custom agents available to the session after reloading definitions from disk. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentReloadResult +{ + /// Reloaded custom agents. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } +} - /// The model ID to use for assistant turns. +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionAgentReloadRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifier assigned to the newly started background agent task. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksStartAgentResult +{ + /// Generated agent ID for the background task. + [JsonPropertyName("agentId")] + public string AgentId { get; set; } = string.Empty; +} + +/// Agent type, prompt, name, and optional description and model override for the new task. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksStartAgentRequest +{ + /// Type of agent to start (e.g., 'explore', 'task', 'general-purpose'). + [JsonPropertyName("agentType")] + public string AgentType { get; set; } = string.Empty; + + /// Short description of the task. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Optional model override. [JsonPropertyName("model")] public string? Model { get; set; } - /// Per-property model capability overrides for the selected model. - [JsonPropertyName("modelCapabilitiesOverrides")] - public ModelCapabilitiesOverride? ModelCapabilitiesOverrides { get; set; } + /// Friendly, non-unique name used when displaying the agent. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Organization-level custom instructions to inject into the system prompt. - [JsonPropertyName("organizationCustomInstructions")] - public string? OrganizationCustomInstructions { get; set; } + /// Task prompt for the agent. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Custom model-provider configuration (BYOK). - [JsonPropertyName("provider")] - public ProviderConfig? Provider { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Reasoning effort for the selected model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } +/// Tracked task union returned by task APIs, containing an agent, client, or shell task. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(TaskInfoAgent), "agent")] +[JsonDerivedType(typeof(TaskInfoClient), "client")] +[JsonDerivedType(typeof(TaskInfoShell), "shell")] +public partial class TaskInfo +{ + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; +} - /// Reasoning summary mode for supported model clients. - [JsonPropertyName("reasoningSummary")] - public OptionsUpdateReasoningSummary? ReasoningSummary { get; set; } - /// Whether the session is running in an interactive UI. - [JsonPropertyName("runningInInteractiveMode")] - public bool? RunningInInteractiveMode { get; set; } +/// Tracked background agent task metadata, including IDs, status, timing, agent type, prompt, model, result, and latest response. +/// The agent variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskInfoAgent : TaskInfo +{ + /// + [JsonIgnore] + public override string Type => "agent"; - /// Resolved sandbox configuration. - [JsonPropertyName("sandboxConfig")] - public SandboxConfig? SandboxConfig { get; set; } + /// ISO 8601 timestamp when the current active period began. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("activeStartedAt")] + public DateTimeOffset? ActiveStartedAt { get; set; } - /// Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("sandboxConfigSource")] - public SandboxConfigSource? SandboxConfigSource { get; set; } + /// Accumulated active execution time in milliseconds. + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("activeTimeMs")] + public TimeSpan? ActiveTime { get; set; } - /// Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. - [JsonPropertyName("sessionCapabilities")] - public IList? SessionCapabilities { get; set; } + /// Type of agent running this task. + [JsonPropertyName("agentType")] + public required string AgentType { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the task is currently in the original sync wait and can be moved to background mode. False once it is already backgrounded, idle, finished, or no longer has a promotable sync waiter. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("canPromoteToBackground")] + public bool? CanPromoteToBackground { get; set; } - /// Optional session limits. Pass null to clear the session limits. - [JsonPropertyName("sessionLimits")] - public SessionLimitsConfig? SessionLimits { get; set; } + /// ISO 8601 timestamp when the task finished. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } - /// Per-session settings for built-in shell tools. - [JsonPropertyName("shell")] - public ShellOptions? Shell { get; set; } + /// Short description of the task. + [JsonPropertyName("description")] + public required string Description { get; set; } - /// Use shell.initProfile instead. Shell init profile (`None` or `NonInteractive`). - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("shellInitProfile")] - public string? ShellInitProfile { get; set; } + /// Friendly, non-unique name intended for display. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Error message when the task failed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Whether task execution is synchronously awaited or managed in the background. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("executionMode")] + public TaskExecutionMode? ExecutionMode { get; set; } + + /// Unique task identifier. + [JsonPropertyName("id")] + public required string Id { get; set; } + + /// ISO 8601 timestamp when the agent entered idle state. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("idleSince")] + public DateTimeOffset? IdleSince { get; set; } + + /// Most recent response text from the agent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("latestResponse")] + public string? LatestResponse { get; set; } + + /// Requested model override for the task when specified. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Most recent prompt delivered to the agent. Updated whenever the agent receives a follow-up message. + [JsonPropertyName("prompt")] + public required string Prompt { get; set; } + + /// Runtime model resolved for the task when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resolvedModel")] + public string? ResolvedModel { get; set; } + + /// Result text from the task when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("result")] + public string? Result { get; set; } + + /// ISO 8601 timestamp when the task was started. + [JsonPropertyName("startedAt")] + public required DateTimeOffset StartedAt { get; set; } + + /// Current lifecycle status of the task. + [JsonPropertyName("status")] + public required TaskStatus Status { get; set; } + + /// Tool call ID associated with this agent task. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } +} + +/// Public owner attribution for a client-owned task. Identifiers are opaque and never authorize requests. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TaskClientOwner +{ + /// ISO 8601 timestamp when the bound join disconnected. + [JsonPropertyName("disconnectedAt")] + public DateTimeOffset? DisconnectedAt { get; set; } + + /// Display-only owner name. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Opaque identity of the currently or most recently bound session join. + [JsonPropertyName("joinId")] + public string JoinId { get; set; } = string.Empty; + + /// Class of the task owner. + [JsonPropertyName("kind")] + public TaskClientOwnerKind Kind { get; set; } + + /// Opaque session-scoped participant identity. + [JsonPropertyName("participantId")] + public string ParticipantId { get; set; } = string.Empty; + + /// Whether this task's bound join is currently connected. + [JsonPropertyName("presence")] + public TaskClientOwnerPresence Presence { get; set; } + + /// Display-only owner source. + [JsonPropertyName("source")] + public string? Source { get; set; } +} + +/// Tracked client-owned task metadata. +/// The client variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskInfoClient : TaskInfo +{ + /// + [JsonIgnore] + public override string Type => "client"; + + /// ISO 8601 timestamp when the current active segment started. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("activeStartedAt")] + public DateTimeOffset? ActiveStartedAt { get; set; } + + /// Accumulated active execution time in milliseconds. + [JsonPropertyName("activeTimeMs")] + public required long ActiveTimeMs { get; set; } + + /// Whether the currently bound owner can receive a cancellation request. + [JsonPropertyName("canCancel")] + public required bool CanCancel { get; set; } + + /// Human-readable reason for terminal cancellation. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cancellationReason")] + public string? CancellationReason { get; set; } + + /// Owner-scoped registration and reclaim key. + [JsonPropertyName("clientTaskId")] + public required string ClientTaskId { get; set; } + + /// ISO 8601 timestamp when the task reached a terminal status. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } + + /// Task description. + [JsonPropertyName("description")] + public required string Description { get; set; } + + /// Optional task display name. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Human-readable terminal failure message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Optional owner-supplied terminal failure code. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("errorCode")] + public string? ErrorCode { get; set; } + + /// Execution mode, which is always background for client-owned tasks. + [JsonPropertyName("executionMode")] + public required TaskClientExecutionMode ExecutionMode { get; set; } + + /// Canonical runtime-generated task identifier. + [JsonPropertyName("id")] + public required string Id { get; set; } + + /// ISO 8601 timestamp when the connected owner entered idle status. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("idleSince")] + public DateTimeOffset? IdleSince { get; set; } + + /// ISO 8601 timestamp of the most recent orphan transition. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("orphanedAt")] + public DateTimeOffset? OrphanedAt { get; set; } + + /// Public attribution and presence for the task owner. + [JsonPropertyName("owner")] + public required TaskClientOwner Owner { get; set; } + + /// ISO 8601 timestamp of the most recent successful reclaim. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reclaimedAt")] + public DateTimeOffset? ReclaimedAt { get; set; } + + /// Opaque successful terminal result supplied by the task owner. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } + + /// Sequence number of the latest accepted owner update. + [JsonPropertyName("sequence")] + public required long Sequence { get; set; } + + /// ISO 8601 timestamp when the task started. + [JsonPropertyName("startedAt")] + public required DateTimeOffset StartedAt { get; set; } + + /// Client task lifecycle status. + [JsonPropertyName("status")] + public required TaskClientStatus Status { get; set; } + + /// ISO 8601 timestamp of the latest accepted lifecycle change. + [JsonPropertyName("updatedAt")] + public required DateTimeOffset UpdatedAt { get; set; } +} + +/// Tracked shell task metadata, including ID, command, status, timing, attachment/execution mode, log path, and PID. +/// The shell variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskInfoShell : TaskInfo +{ + /// + [JsonIgnore] + public override string Type => "shell"; + + /// Whether the shell runs inside a managed PTY session or as an independent background process. + [JsonPropertyName("attachmentMode")] + public required TaskShellInfoAttachmentMode AttachmentMode { get; set; } + + /// Whether this shell task can be promoted to background mode. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("canPromoteToBackground")] + public bool? CanPromoteToBackground { get; set; } + + /// Command being executed. + [JsonPropertyName("command")] + public required string Command { get; set; } + + /// ISO 8601 timestamp when the task finished. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } + + /// Short description of the task. + [JsonPropertyName("description")] + public required string Description { get; set; } + + /// Whether task execution is synchronously awaited or managed in the background. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("executionMode")] + public TaskExecutionMode? ExecutionMode { get; set; } + + /// Unique task identifier. + [JsonPropertyName("id")] + public required string Id { get; set; } + + /// Path to the detached shell log, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("logPath")] + public string? LogPath { get; set; } + + /// Process ID when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pid")] + public long? Pid { get; set; } + + /// ISO 8601 timestamp when the task was started. + [JsonPropertyName("startedAt")] + public required DateTimeOffset StartedAt { get; set; } + + /// Current lifecycle status of the task. + [JsonPropertyName("status")] + public required TaskStatus Status { get; set; } +} + +/// Background tasks currently tracked by the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TaskList +{ + /// Currently tracked tasks. + [JsonPropertyName("tasks")] + public IList Tasks { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTasksListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Tracked client-owned task metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TaskClientInfo +{ + /// ISO 8601 timestamp when the current active segment started. + [JsonPropertyName("activeStartedAt")] + public DateTimeOffset? ActiveStartedAt { get; set; } + + /// Accumulated active execution time in milliseconds. + [JsonPropertyName("activeTimeMs")] + public long ActiveTimeMs { get; set; } + + /// Whether the currently bound owner can receive a cancellation request. + [JsonPropertyName("canCancel")] + public bool CanCancel { get; set; } + + /// Human-readable reason for terminal cancellation. + [JsonPropertyName("cancellationReason")] + public string? CancellationReason { get; set; } + + /// Owner-scoped registration and reclaim key. + [JsonPropertyName("clientTaskId")] + public string ClientTaskId { get; set; } = string.Empty; + + /// ISO 8601 timestamp when the task reached a terminal status. + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } + + /// Task description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Optional task display name. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Human-readable terminal failure message. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Optional owner-supplied terminal failure code. + [JsonPropertyName("errorCode")] + public string? ErrorCode { get; set; } + + /// Execution mode, which is always background for client-owned tasks. + [JsonPropertyName("executionMode")] + public TaskClientExecutionMode ExecutionMode { get; set; } + + /// Canonical runtime-generated task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// ISO 8601 timestamp when the connected owner entered idle status. + [JsonPropertyName("idleSince")] + public DateTimeOffset? IdleSince { get; set; } + + /// ISO 8601 timestamp of the most recent orphan transition. + [JsonPropertyName("orphanedAt")] + public DateTimeOffset? OrphanedAt { get; set; } + + /// Public attribution and presence for the task owner. + [JsonPropertyName("owner")] + public TaskClientOwner Owner { get => field ??= new(); set; } + + /// ISO 8601 timestamp of the most recent successful reclaim. + [JsonPropertyName("reclaimedAt")] + public DateTimeOffset? ReclaimedAt { get; set; } + + /// Opaque successful terminal result supplied by the task owner. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } + + /// Sequence number of the latest accepted owner update. + [JsonPropertyName("sequence")] + public long Sequence { get; set; } + + /// ISO 8601 timestamp when the task started. + [JsonPropertyName("startedAt")] + public DateTimeOffset StartedAt { get; set; } + + /// Client task lifecycle status. + [JsonPropertyName("status")] + public TaskClientStatus Status { get; set; } + + /// Task kind. + [JsonPropertyName("type")] + public TaskClientType Type { get; set; } + + /// ISO 8601 timestamp of the latest accepted lifecycle change. + [JsonPropertyName("updatedAt")] + public DateTimeOffset UpdatedAt { get; set; } +} + +/// Result of registering or reclaiming a client-owned task. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksRegisterResult +{ + /// True only when this invocation created a new task. + [JsonPropertyName("created")] + public bool Created { get; set; } + + /// True only when this invocation reclaimed an orphaned task. + [JsonPropertyName("reclaimed")] + public bool Reclaimed { get; set; } + + /// Authoritative registered or reclaimed task. + [JsonPropertyName("task")] + public TaskClientInfo Task { get => field ??= new(); set; } +} + +/// Registers or reclaims a client-owned task. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksRegisterRequest +{ + /// Whether the owner supports runtime cancellation requests. + [JsonPropertyName("cancellable")] + public bool Cancellable { get; set; } + + /// Owner-scoped idempotency key used for registration and reclaim. + [JsonPropertyName("clientTaskId")] + public string ClientTaskId { get; set; } = string.Empty; + + /// Human-readable description of the external work. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Optional short display name for the external work. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Expected current sequence for idempotent registration or orphan reclaim. + [JsonPropertyName("expectedSequence")] + public long? ExpectedSequence { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Task kind. + [JsonPropertyName("type")] + public TaskClientType Type { get; set; } +} + +/// Result of publishing a client-owned task update. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksUpdateResult +{ + /// Whether this invocation changed task state. + [JsonPropertyName("applied")] + public bool Applied { get; set; } + + /// Whether this invocation repeated the latest accepted update. + [JsonPropertyName("duplicate")] + public bool Duplicate { get; set; } + + /// Authoritative task after processing the update. + [JsonPropertyName("task")] + public TaskClientInfo Task { get => field ??= new(); set; } +} + +/// Progress or terminal update for a client-owned task. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(TaskClientUpdateProgress), "progress")] +[JsonDerivedType(typeof(TaskClientUpdateCompleted), "completed")] +[JsonDerivedType(typeof(TaskClientUpdateFailed), "failed")] +[JsonDerivedType(typeof(TaskClientUpdateCancelled), "cancelled")] +public partial class TaskClientUpdate +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} + + +/// Publishes nonterminal progress for a running or idle client task. +/// The progress variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskClientUpdateProgress : TaskClientUpdate +{ + /// + [JsonIgnore] + public override string Kind => "progress"; + + /// Optional progress message appended to recent activity when nonempty. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// Optional completion percentage; null clears the current percentage. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("percentage")] + public double? Percentage { get; set; } + + /// Optional progress phase; null clears the current phase. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("phase")] + public string? Phase { get; set; } + + /// Optional active status transition. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("status")] + public TaskClientActiveStatus? Status { get; set; } +} + +/// Reports successful terminal completion. +/// The completed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskClientUpdateCompleted : TaskClientUpdate +{ + /// + [JsonIgnore] + public override string Kind => "completed"; + + /// Optional final progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// Optional opaque successful terminal result. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } +} + +/// Reports terminal failure. +/// The failed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskClientUpdateFailed : TaskClientUpdate +{ + /// + [JsonIgnore] + public override string Kind => "failed"; + + /// Optional owner-supplied terminal failure code. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("code")] + public string? Code { get; set; } + + /// Human-readable terminal failure message. + [JsonPropertyName("error")] + public required string Error { get; set; } + + /// Optional final progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } +} + +/// Reports terminal cancellation after external work stopped. +/// The cancelled variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskClientUpdateCancelled : TaskClientUpdate +{ + /// + [JsonIgnore] + public override string Kind => "cancelled"; + + /// Optional final progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// Optional human-readable cancellation reason. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reason")] + public string? Reason { get; set; } +} + +/// Updates a client-owned task. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksUpdateRequest +{ + /// Canonical runtime-generated task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Owner update sequence to apply. + [JsonPropertyName("sequence")] + public long Sequence { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Progress or terminal update payload. + [JsonPropertyName("update")] + public TaskClientUpdate Update { get => field ??= new(); set; } +} + +/// 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. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksRefreshResult +{ +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTasksRefreshRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Wait until all in-flight background tasks (agents + shells) and any follow-up 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). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksWaitForPendingResult +{ +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTasksWaitForPendingRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(TaskProgressAgent), "agent")] +[JsonDerivedType(typeof(TaskProgressClient), "client")] +[JsonDerivedType(typeof(TaskProgressShell), "shell")] +public partial class TaskProgress +{ + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; +} + + +/// Timestamped display line for task progress output or recent agent activity. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TaskProgressLine +{ + /// Display message, e.g., "▸ bash", "✓ edit src/foo.ts". + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// ISO 8601 timestamp when this event occurred. + [JsonPropertyName("timestamp")] + public DateTimeOffset Timestamp { get; set; } +} + +/// Progress snapshot for an agent task, with recent activity lines and optional latest intent. +/// The agent variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskProgressAgent : TaskProgress +{ + /// + [JsonIgnore] + public override string Type => "agent"; + + /// The most recent intent reported by the agent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("latestIntent")] + public string? LatestIntent { get; set; } + + /// Recent tool execution events converted to display lines. + [JsonPropertyName("recentActivity")] + public required IList RecentActivity { get; set; } +} + +/// Generic progress for a client-owned task. +/// The client variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskProgressClient : TaskProgress +{ + /// + [JsonIgnore] + public override string Type => "client"; + + /// Most recent nonempty progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("lastMessage")] + public string? LastMessage { get; set; } + + /// Current completion percentage from zero through one hundred. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("percentage")] + public double? Percentage { get; set; } + + /// Current owner-defined progress phase. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("phase")] + public string? Phase { get; set; } + + /// Recent server-timestamped progress messages. + [JsonPropertyName("recentActivity")] + public required IList RecentActivity { get; set; } + + /// Sequence number of the latest accepted owner update. + [JsonPropertyName("sequence")] + public required long Sequence { get; set; } + + /// Current client task lifecycle status. + [JsonPropertyName("status")] + public required TaskClientStatus Status { get; set; } + + /// ISO 8601 timestamp of the latest accepted lifecycle change. + [JsonPropertyName("updatedAt")] + public required DateTimeOffset UpdatedAt { get; set; } +} + +/// Progress snapshot for a shell task, with recent stdout/stderr output and optional process ID. +/// The shell variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class TaskProgressShell : TaskProgress +{ + /// + [JsonIgnore] + public override string Type => "shell"; + + /// Process ID when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pid")] + public long? Pid { get; set; } + + /// Recent stdout/stderr lines from the running shell command. + [JsonPropertyName("recentOutput")] + public required string RecentOutput { get; set; } +} + +/// Progress information for the task, or null when no task with that ID is tracked. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksGetProgressResult +{ + /// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. + [JsonPropertyName("progress")] + public TaskProgress? Progress { get; set; } +} + +/// Identifier of the background task to fetch progress for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksGetProgressRequest +{ + /// Task identifier (agent ID or shell ID). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The first sync-waiting task that can currently be promoted to background mode. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksGetCurrentPromotableResult +{ + /// The first sync-waiting task (agent first, then shell) that can currently be promoted to background mode. Omitted if no such task exists. The returned task is guaranteed to have executionMode='sync' and canPromoteToBackground=true at the time of the call. + [JsonPropertyName("task")] + public TaskInfo? Task { get; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTasksGetCurrentPromotableRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the task was successfully promoted to background mode. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksPromoteToBackgroundResult +{ + /// Whether the task was successfully promoted to background mode. + [JsonPropertyName("promoted")] + public bool Promoted { get; set; } +} + +/// Identifier of the task to promote to background mode. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksPromoteToBackgroundRequest +{ + /// Task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksPromoteCurrentToBackgroundResult +{ + /// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. Atomic operation: avoids the race window of getCurrentPromotable + promoteToBackground. + [JsonPropertyName("task")] + public TaskInfo? Task { get; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTasksPromoteCurrentToBackgroundRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the background task was successfully cancelled. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksCancelResult +{ + /// Whether the task was successfully cancelled. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } +} + +/// Identifier of the background task to cancel. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksCancelRequest +{ + /// Task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the task was removed. False when the task does not exist or is still running/idle. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksRemoveResult +{ + /// Whether the task was removed. Returns false if the task does not exist or is still running/idle (cancel it first). + [JsonPropertyName("removed")] + public bool Removed { get; set; } +} + +/// Identifier of the completed or cancelled task to remove from tracking. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksRemoveRequest +{ + /// Task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the message was delivered, with an error message when delivery failed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksSendMessageResult +{ + /// Error message if delivery failed. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Whether the message was successfully delivered or steered. + [JsonPropertyName("sent")] + public bool Sent { get; set; } +} + +/// Identifier of the target agent task, message content, and optional sender agent ID. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksSendMessageRequest +{ + /// Agent ID of the sender, if sent on behalf of another agent. + [JsonPropertyName("fromAgentId")] + public string? FromAgentId { get; set; } + + /// Agent task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Message content to send to the agent. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Skill metadata available to a session, with name, description, source, enabled/invocable state, path, plugin, and argument hint. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class Skill +{ + /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. + [JsonPropertyName("argumentHint")] + public string? ArgumentHint { get; set; } + + /// Canonical slash command name used to invoke the skill, without the leading '/'. + [JsonPropertyName("commandName")] + public string? CommandName { get; set; } + + /// Description of what the skill does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Whether the skill is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Unique identifier for the skill. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Absolute path to the skill file. + [JsonPropertyName("path")] + public string? Path { get; set; } + + /// Name of the plugin that provides the skill, when source is 'plugin'. + [JsonPropertyName("pluginName")] + public string? PluginName { get; set; } + + /// Source location type (e.g., project, personal-copilot, plugin, builtin). + [JsonPropertyName("source")] + public SkillSource Source { get; set; } + + /// Whether the skill can be invoked by the user as a slash command. + [JsonPropertyName("userInvocable")] + public bool UserInvocable { get; set; } +} + +/// Skills available to the session, with their enabled state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SkillList +{ + /// Available skills. + [JsonPropertyName("skills")] + public IList Skills { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSkillsListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Skill invocation record with name, path, content, allowed tools, and turn number. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SkillsInvokedSkill +{ + /// Tools that should be auto-approved when this skill is active, captured at invocation time. + [JsonPropertyName("allowedTools")] + public IList? AllowedTools { get; set; } + + /// Full content of the skill file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Whether model invocation was disabled when this skill was invoked. + [JsonPropertyName("disableModelInvocation")] + public bool? DisableModelInvocation { get; set; } + + /// Turn number when the skill was invoked. + [JsonPropertyName("invokedAtTurn")] + public long InvokedAtTurn { get; set; } + + /// Unique identifier for the skill. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Path to the SKILL.md file, or an empty string for an SDK-provided skill without a filesystem identity. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} + +/// Skills invoked during this session, ordered by invocation time (most recent last). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SkillsGetInvokedResult +{ + /// Skills invoked during this session, ordered by invocation time (most recent last). + [JsonPropertyName("skills")] + public IList Skills { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSkillsGetInvokedRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name of the skill to enable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SkillsEnableRequest +{ + /// Name of the skill to enable. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name of the skill to disable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SkillsDisableRequest +{ + /// Name of the skill to disable. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Diagnostics from reloading skill definitions, with warnings and errors as separate lists. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SkillsLoadDiagnostics +{ + /// Errors emitted while loading skills (e.g. skills that failed to load entirely). + [JsonPropertyName("errors")] + public IList Errors { get => field ??= []; set; } + + /// Warnings emitted while loading skills (e.g. skills that loaded but had issues). + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSkillsReloadRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSkillsEnsureLoadedRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The IDE a host is connected to, as reported to the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionConnectedIdeInfo +{ + /// Display name of the connected IDE, for example `VS Code`. + [JsonPropertyName("ideName")] + public string IdeName { get; set; } = string.Empty; + + /// Absolute path of the workspace folder the IDE has open. + [JsonPropertyName("workspaceFolder")] + public string WorkspaceFolder { get; set; } = string.Empty; +} + +/// Records which IDE the host is connected to, or clears it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpSetConnectedIdeInfoParams +{ + /// The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports that it is disconnected. + [JsonPropertyName("ide")] + public SessionConnectedIdeInfo? Ide { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Recorded MCP server connection failure. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpServerFailureInfo +{ + /// Failure message produced when the MCP server connection failed. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// epoch-ms timestamp at which the failure was recorded. + [JsonPropertyName("timestamp")] + public long Timestamp { get; set; } +} + +/// Recorded MCP server pending-auth state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpServerNeedsAuthInfo +{ + /// epoch-ms timestamp at which the server signalled it needs authentication. + [JsonPropertyName("timestamp")] + public long Timestamp { get; set; } +} + +/// Host-level state, omitted when no MCP host is initialized. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpHostState +{ + /// Names of currently-connected MCP clients. + [JsonPropertyName("clients")] + public IList Clients { get => field ??= []; set; } + + /// Configured servers that are explicitly disabled. + [JsonPropertyName("disabledServers")] + public IList DisabledServers { get => field ??= []; set; } + + /// Map of server name to recorded connection failure. + [JsonPropertyName("failedServers")] + public IDictionary FailedServers { get => field ??= new Dictionary(); set; } + + /// Configured servers filtered out by MCP server policy. + [JsonPropertyName("filteredServers")] + public IList FilteredServers { get => field ??= []; set; } + + /// Whether third-party MCP servers are policy-enabled for this session. + [JsonPropertyName("mcp3pEnabled")] + public bool Mcp3pEnabled { get; set; } + + /// Map of server name to recorded pending-auth state. + [JsonPropertyName("needsAuthServers")] + public IDictionary NeedsAuthServers { get => field ??= new Dictionary(); set; } + + /// Names of servers with in-flight connection attempts. + [JsonPropertyName("pendingConnections")] + public IList PendingConnections { get => field ??= []; set; } +} + +/// Owned installation that a listed MCP server's live configuration came from. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpServerOwnership +{ + /// Stable installation identifier from the owned installation receipt. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; +} + +/// MCP server status entry, including config source/plugin source and any connection error. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpServer +{ + /// Human-readable display name supplied by a managed server catalog. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Error message if the server failed to connect. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Server name (config key). + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("name")] + public string Name { get; set; } = string.Empty; + + /// Owned installation this entry's live configuration came from. Absent for manual, workspace, plugin, builtin and same-name servers, and on runtimes without owned installations. + [JsonPropertyName("owned")] + public McpServerOwnership? Owned { get; set; } + + /// Server-advertised metadata for a connected server. Omitted when no live connection metadata is available, including while pending or when failed, disabled, stopped, or not configured. + [JsonPropertyName("serverMetadata")] + public McpServerMetadata? ServerMetadata { get; set; } + + /// Configuration source: user, workspace, plugin, builtin, or managed. + [JsonPropertyName("source")] + public McpServerSource? Source { get; set; } + + /// Plugin name that provided this server, when source is plugin. + [JsonPropertyName("sourcePlugin")] + public string? SourcePlugin { get; set; } + + /// Plugin version that provided this server, when source is plugin. + [JsonPropertyName("sourcePluginVersion")] + public string? SourcePluginVersion { get; set; } + + /// Connection status: connected, failed, needs-auth, pending, disabled, stopped, or not_configured. + [JsonPropertyName("status")] + public McpServerStatus Status { get; set; } + + /// Configured URL for an HTTP/SSE server, regardless of configuration source. Omitted for local and in-memory servers. + [JsonPropertyName("url")] + public string? Url { get; set; } +} + +/// MCP servers configured for the session, with their connection status and host-level state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpServerList +{ + /// Host-level state, omitted when no MCP host is initialized. + [JsonPropertyName("host")] + public McpHostState? Host { get; set; } + + /// Configured MCP servers. + [JsonPropertyName("servers")] + public IList Servers { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Observational state for a matching already materialized MCP server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpConfiguredServerState +{ + /// Observed connection error, when the materialized server failed. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Observed connection status. This is not a configuration or readiness guarantee. + [JsonPropertyName("status")] + public McpServerStatus Status { get; set; } +} + +/// Effective MCP configuration entry. Configuration enablement is distinct from the optional live observation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpConfiguredServer +{ + /// Human-readable display name supplied by configuration. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Whether this configured server is enabled after session configuration and policy filtering. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Observed state from an already materialized matching server. Omitted when no live graph has this configured server; it never determines configuration enablement. + [JsonPropertyName("live")] + public McpConfiguredServerState Live { get => field ??= new(); set; } + + /// Server name (config key). + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("name")] + public string Name { get; set; } = string.Empty; + + /// Configuration provenance: user, workspace, plugin, builtin, or managed. + [JsonPropertyName("source")] + public McpServerSource? Source { get; set; } + + /// Plugin name that provided this server, when source is plugin. + [JsonPropertyName("sourcePlugin")] + public string? SourcePlugin { get; set; } + + /// Plugin version that provided this server, when source is plugin. + [JsonPropertyName("sourcePluginVersion")] + public string? SourcePluginVersion { get; set; } +} + +/// Effective MCP configuration with optional live observations from matching already materialized servers. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpConfiguredServerList +{ + /// Effective configured MCP servers. + [JsonPropertyName("servers")] + public IList Servers { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpListConfiguredRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Normalized MCP Apps discovery metadata from a tool's `_meta.ui` block. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpToolUi +{ + /// URI of the tool's MCP App resource, typically a `ui://` resource identifier. Use `session.mcp.resources.read` to fetch its HTML and resource metadata. + [JsonPropertyName("resourceUri")] + public string? ResourceUri { get; set; } + + /// Tool visibility advertised by the server. When absent, MCP Apps defaults apply. + [JsonPropertyName("visibility")] + public IList? Visibility { get; set; } +} + +/// MCP tool metadata with tool name, optional description, and normalized MCP Apps discovery metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpTools +{ + /// Tool description, when provided. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Tool name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Normalized MCP Apps discovery metadata. An empty object indicates that a valid `_meta.ui` block was present without recognized fields. + [JsonPropertyName("ui")] + public McpToolUi? Ui { get; set; } +} + +/// Tools exposed by the connected MCP server. Throws when the server is not connected. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpListToolsResult +{ + /// Tools exposed by the server. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } +} + +/// Server name whose tool list should be returned. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpListToolsRequest +{ + /// Name of the connected MCP server whose tools to list. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name of the MCP server to enable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpEnableRequest +{ + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to enable. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public required string ServerName { get; set; } +} + +/// Name of the MCP server to enable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpEnableRequestWithSession +{ + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to enable. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name of the MCP server to disable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpDisableRequest +{ + /// Required for an owned installation; omission preserves only manual-server behaviour. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to disable. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public required string ServerName { get; set; } +} + +/// Name of the MCP server to disable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpDisableRequestWithSession +{ + /// Required for an owned installation; omission preserves only manual-server behaviour. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to disable. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpReloadRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Result of moving in-flight MCP loading to the background. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MoveMcpLoadingToBackgroundResult +{ + /// Whether an in-flight MCP load was moved to the background, releasing turns that were waiting on it. False when no MCP load was in flight or the waiting turns had already been released. + [JsonPropertyName("movedToBackground")] + public bool MovedToBackground { get; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpMoveLoadingToBackgroundRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// MCP server allowed by policy, with server name and optional PII-free explanatory note. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAllowedServer +{ + /// Allowed server name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// PII-free note explaining why the server was allowed. + [JsonPropertyName("redactedNote")] + public string? RedactedNote { get; set; } +} + +/// MCP server whose connection attempt failed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpFailedServer +{ + /// The captured connection failure detail. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// The config key of the server that failed to connect. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} + +/// MCP server filtered by policy, with name, reason, and optional redacted reason. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpFilteredServer +{ + /// Deprecated. This field is no longer populated. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("enterpriseName")] + public string? EnterpriseName { get; set; } + + /// Filtered server name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Human-readable filter reason. + [JsonPropertyName("reason")] + public string Reason { get; set; } = string.Empty; + + /// PII-free filter reason. + [JsonPropertyName("redactedReason")] + public string? RedactedReason { get; set; } +} + +/// MCP server startup filtering result. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpStartServersResult +{ + /// Non-default servers allowed by policy. + [JsonPropertyName("allowedServers")] + public IList? AllowedServers { get; set; } + + /// Servers whose connection attempt failed. + [JsonPropertyName("failedServers")] + public IList? FailedServers { get; set; } + + /// Servers filtered out before startup. + [JsonPropertyName("filteredServers")] + public IList FilteredServers { get => field ??= []; set; } +} + +/// Opaque MCP reload configuration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpReloadWithConfigRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Outcome of an MCP sampling execution: success result, failure error, or cancellation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpSamplingExecutionResult +{ + /// 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. + [JsonPropertyName("action")] + public McpSamplingExecutionAction Action { get; set; } + + /// Error description, present when action='failure'. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// 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. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } +} + +/// Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpExecuteSamplingParams +{ + /// 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). + [JsonPropertyName("mcpRequestId")] + public JsonElement McpRequestId { get; set; } + + /// 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. + [JsonPropertyName("request")] + public JsonElement Request { get; set; } + + /// 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. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Name of the MCP server that initiated the sampling request. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpCancelSamplingExecutionResult +{ + /// 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). + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } +} + +/// The requestId previously passed to executeSampling that should be cancelled. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpCancelSamplingExecutionParams +{ + /// The requestId previously passed to executeSampling that should be cancelled. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Env-value mode recorded on the session after the update. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpSetEnvValueModeResult +{ + /// Mode recorded on the session after the update. + [JsonPropertyName("mode")] + public McpSetEnvValueModeDetails Mode { get; set; } +} + +/// Mode controlling how MCP server env values are resolved (`direct` or `indirect`). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpSetEnvValueModeParams +{ + /// 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". + [JsonPropertyName("mode")] + public McpSetEnvValueModeDetails Mode { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpRemoveGitHubResult +{ + /// 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). + [JsonPropertyName("removed")] + public bool Removed { get; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpRemoveGitHubRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Result of configuring GitHub MCP. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpConfigureGitHubResult +{ + /// Whether GitHub MCP configuration changed. + [JsonPropertyName("changed")] + public bool Changed { get; set; } +} + +/// Credential-free authentication identity used to configure GitHub MCP. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpConfigureGitHubRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpStartServerRequest +{ + /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } + + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to start. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } +} + +/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpStartServerRequestWithSession +{ + /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } + + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to start. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpRestartServerRequest +{ + /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } + + /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to restart. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } +} + +/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRestartServerRequestWithSession +{ + /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } + + /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to restart. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Server name for an individual MCP server stop. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpStopServerRequest +{ + /// Exact owned receipt identity. Stop also forgets this session's durable activation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to stop. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } +} + +/// Server name for an individual MCP server stop. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpStopServerRequestWithSession +{ + /// Exact owned receipt identity. Stop also forgets this session's durable activation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to stop. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Registration parameters for an external MCP client. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegisterExternalClientRequest +{ + /// Logical server name for the external client. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Server name identifying the external client to remove. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpUnregisterExternalClientRequest +{ + /// Server name of the external client to unregister. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Whether the named MCP server is running. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpIsServerRunningResult +{ + /// True if the server has an active client and transport. + [JsonPropertyName("running")] + public bool Running { get; set; } +} + +/// Server name to check running status for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpIsServerRunningRequest +{ + /// Name of the MCP server to check. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the pending MCP OAuth response was accepted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpOauthHandlePendingResult +{ + /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// Host response to the pending OAuth request. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpOauthPendingRequestResponseToken), "token")] +[JsonDerivedType(typeof(McpOauthPendingRequestResponseCancelled), "cancelled")] +public partial class McpOauthPendingRequestResponse +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} + + +/// The token variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpOauthPendingRequestResponseToken : McpOauthPendingRequestResponse +{ + /// + [JsonIgnore] + public override string Kind => "token"; + + /// Access token acquired by the SDK host. + [JsonPropertyName("accessToken")] + public required string AccessToken { get; set; } + + /// Token lifetime in seconds, if known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("expiresIn")] + public long? ExpiresIn { get; set; } + + /// OAuth token type. Defaults to bearer when omitted. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("tokenType")] + public string? TokenType { get; set; } +} + +/// The cancelled variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpOauthPendingRequestResponseCancelled : McpOauthPendingRequestResponse +{ + /// + [JsonIgnore] + public override string Kind => "cancelled"; +} + +/// Pending MCP OAuth request ID and host-provided token or cancellation response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpOauthHandlePendingRequest +{ + /// OAuth request identifier from the mcp.oauth_required event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Host response to the pending OAuth request. + [JsonPropertyName("result")] + public McpOauthPendingRequestResponse Result { get => field ??= new(); set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the MCP server whose persisted OAuth credentials were updated. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpOauthAuthenticationStateChangedRequest +{ + /// Whether the target session must mint a session-scoped access token instead of reusing a shared access token persisted by another session. + [JsonPropertyName("refreshSessionToken")] + public bool? RefreshSessionToken { get; set; } + + /// Name of the MCP server whose OAuth credentials were updated. Omit only when the host cannot identify the server. + [JsonPropertyName("serverName")] + public string? ServerName { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionMcpOauthPrepareLoginResult +{ + /// Original expiry, not extended by consumption, retries or cancellation. + [JsonPropertyName("expiresAt")] + public DateTimeOffset ExpiresAt { get; set; } + + /// Retain with the original requester and use for one login or cancellation. + [JsonPropertyName("loginId")] + public string LoginId { get; set; } = string.Empty; +} + +/// Effect-free preparation bound to the existing local session, requester and installation, with frozen options. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpOauthPrepareLoginRequest +{ + /// Text shown on the loopback callback page after successful authorisation. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(2048)] + [JsonPropertyName("callbackSuccessMessage")] + public string? CallbackSuccessMessage { get; set; } + + /// Display name used by the incumbent OAuth client-registration flow. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(2048)] + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Exact installation identity from owned inventory, never a server-name alias. + [JsonPropertyName("expectedInstallationId")] + public string ExpectedInstallationId { get; set; } = string.Empty; + + /// Request a new authorisation rather than accepting a usable cached grant. + [JsonPropertyName("forceReauth")] + public bool? ForceReauth { get; set; } + + /// Name recorded by the authoritative owned installation receipt. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpOauthLoginResult +{ + /// Opaque authorization identifier returned only for a host-managed redirect URI. The runtime also sends it as the OAuth state value, so the callback endpoint can read state and pass it with the full callback URL to session.mcp.oauth.complete. + [JsonPropertyName("authorizationId")] + public string? AuthorizationId { get; set; } + + /// 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. For the default loopback flow, the runtime starts its listener before returning. With redirectUri, the host receives the callback and completes it through session.mcp.oauth.complete. The runtime continues the flow in the background and signals completion via session.mcp_server_status_changed. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("authorizationUrl")] + public string? AuthorizationUrl { get; set; } + + /// Runtime-issued owned flow identity; never a server name or installation operation ID. + [JsonPropertyName("loginId")] + public string? LoginId { get; set; } + + /// Explicit outcome for owned sign-in. Manual callers retain their legacy response shape. + [JsonPropertyName("status")] + public McpOwnedOauthLoginStatus? Status { get; set; } +} + +/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpOauthLoginRequest +{ + /// 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. + [JsonPropertyName("callbackSuccessMessage")] + public string? CallbackSuccessMessage { get; set; } + + /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. + [JsonPropertyName("clientId")] + public string? ClientId { get; set; } + + /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. + [JsonPropertyName("clientSecret")] + public string? ClientSecret { get; set; } + + /// Exact owned receipt identity. Owned login never uses an implicit helper session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. + [JsonPropertyName("forceReauth")] + public bool? ForceReauth { get; set; } + + /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. + [JsonPropertyName("grantType")] + public McpOauthLoginGrantType? GrantType { get; set; } + + /// + /// Required for owned login. Consumes the exact prepareLogin handle once. + /// Set forceReauth and display options during preparation, not consumption. + /// + [JsonPropertyName("loginId")] + public string? LoginId { get; set; } + + /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. + [JsonPropertyName("publicClient")] + public bool? PublicClient { get; set; } + + /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("redirectUri")] + public string? RedirectUri { get; set; } + + /// Name of the remote MCP server to authenticate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public required string ServerName { get; set; } +} + +/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpOauthLoginRequestWithSession +{ + /// 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. + [JsonPropertyName("callbackSuccessMessage")] + public string? CallbackSuccessMessage { get; set; } + + /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. + [JsonPropertyName("clientId")] + public string? ClientId { get; set; } + + /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. + [JsonPropertyName("clientSecret")] + public string? ClientSecret { get; set; } + + /// Exact owned receipt identity. Owned login never uses an implicit helper session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. + [JsonPropertyName("forceReauth")] + public bool? ForceReauth { get; set; } + + /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. + [JsonPropertyName("grantType")] + public McpOauthLoginGrantType? GrantType { get; set; } + + /// + /// Required for owned login. Consumes the exact prepareLogin handle once. + /// Set forceReauth and display options during preparation, not consumption. + /// + [JsonPropertyName("loginId")] + public string? LoginId { get; set; } + + /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. + [JsonPropertyName("publicClient")] + public bool? PublicClient { get; set; } + + /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("redirectUri")] + public string? RedirectUri { get; set; } + + /// Name of the remote MCP server to authenticate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Host-delivered callback for a runtime-managed MCP OAuth login. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpOauthCompleteRequest +{ + /// Opaque identifier returned by session.mcp.oauth.login for the pending external callback. + [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("authorizationId")] + public string AuthorizationId { get; set; } = string.Empty; + + /// Full externally visible HTTPS callback URL received by the host, including the authorization response query parameters. Applications behind a reverse proxy must reconstruct the public URL rather than passing an internal proxy URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("callbackUrl")] + public string CallbackUrl { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Passive MCP OAuth probe result. `authenticated` means the server accepted the probe request while an OAuth-origin access token was attached; it does not prove the server required or independently validated that token. The probe does not make a second unauthenticated request. Failed is an expected probe-domain outcome; JSON-RPC errors are reserved for API-call failures. +/// Polymorphic base type discriminated by status. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "status", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpOauthProbeResultNoAuthRequired), "no-auth-required")] +[JsonDerivedType(typeof(McpOauthProbeResultAuthenticated), "authenticated")] +[JsonDerivedType(typeof(McpOauthProbeResultNeedsAuth), "needs-auth")] +[JsonDerivedType(typeof(McpOauthProbeResultFailed), "failed")] +public partial class McpOauthProbeResult +{ + /// The type discriminator. + [JsonPropertyName("status")] + public virtual string Status { get; set; } = string.Empty; +} + + +/// The no-auth-required variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpOauthProbeResultNoAuthRequired : McpOauthProbeResult +{ + /// + [JsonIgnore] + public override string Status => "no-auth-required"; + + /// HTTP response returned by the server. + [JsonPropertyName("httpResponse")] + public required McpOauthHttpResponse HttpResponse { get; set; } +} + +/// The authenticated variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpOauthProbeResultAuthenticated : McpOauthProbeResult +{ + /// + [JsonIgnore] + public override string Status => "authenticated"; + + /// HTTP response returned by the server. + [JsonPropertyName("httpResponse")] + public required McpOauthHttpResponse HttpResponse { get; set; } +} + +/// The needs-auth variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpOauthProbeResultNeedsAuth : McpOauthProbeResult +{ + /// + [JsonIgnore] + public override string Status => "needs-auth"; + + /// HTTP 401 or 403 response returned by the server. + [JsonPropertyName("httpResponse")] + public required McpOauthHttpResponse HttpResponse { get; set; } + + /// Why authentication is needed. + [JsonPropertyName("reason")] + public required McpOauthProbeNeedsAuthReason Reason { get; set; } + + /// Parsed WWW-Authenticate challenge parameters, when present and parseable. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("wwwAuthenticateParams")] + public McpOauthWWWAuthenticateParams? WwwAuthenticateParams { get; set; } +} + +/// The failed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpOauthProbeResultFailed : McpOauthProbeResult +{ + /// + [JsonIgnore] + public override string Status => "failed"; + + /// Human-readable probe failure detail. + [JsonPropertyName("error")] + public required string Error { get; set; } + + /// HTTP response returned by the server, when the probe reached the server and captured the complete response. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("httpResponse")] + public McpOauthHttpResponse? HttpResponse { get; set; } +} + +/// Remote MCP server name for a passive OAuth status probe. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpOauthProbeRequest +{ + /// Exact owned receipt identity; probing never activates a dormant installation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the configured remote MCP server to probe. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public required string ServerName { get; set; } +} + +/// Remote MCP server name for a passive OAuth status probe. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpOauthProbeRequestWithSession +{ + /// Exact owned receipt identity; probing never activates a dormant installation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the configured remote MCP server to probe. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Honest terminal cancellation result; persistence or recovery failures remain RPC errors. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionMcpOauthCancelLoginResult +{ + /// True after cancellation settles, false when the original login already connected successfully. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } +} + +/// Targets only the original prepared/applying owned login on this exact session requester. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpOauthCancelLoginRequest +{ + /// The same authoritative installation identity supplied during preparation. + [JsonPropertyName("expectedInstallationId")] + public string ExpectedInstallationId { get; set; } = string.Empty; + + /// Runtime-issued login handle known before the effectful login request begins. + [JsonPropertyName("loginId")] + public string LoginId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the pending MCP OAuth response was accepted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpOauthRespondResult +{ + /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// Pending MCP OAuth request id to respond to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpOauthRespondRequest +{ + /// OAuth request identifier from the mcp.oauth_required event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the pending MCP headers refresh response was accepted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpHeadersHandlePendingHeadersRefreshRequestResult +{ + /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// Host response: supply dynamic headers or decline this refresh. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestHeaders), "headers")] +[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestNone), "none")] +[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestError), "error")] +public partial class McpHeadersHandlePendingHeadersRefreshRequest +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} + + +/// The headers variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpHeadersHandlePendingHeadersRefreshRequestHeaders : McpHeadersHandlePendingHeadersRefreshRequest +{ + /// + [JsonIgnore] + public override string Kind => "headers"; + + /// Headers to overlay onto the MCP request. Dynamic headers override static config headers but do not replace SDK-managed request headers. + [JsonPropertyName("headers")] + public required IDictionary Headers { get; set; } + + /// Optional lifetime in milliseconds for these returned headers. The runtime clamps its configured cache lifetime to this value. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ttlMs")] + public long? TtlMs { get; set; } +} + +/// The none variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpHeadersHandlePendingHeadersRefreshRequestNone : McpHeadersHandlePendingHeadersRefreshRequest +{ + /// + [JsonIgnore] + public override string Kind => "none"; +} + +/// The error variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpHeadersHandlePendingHeadersRefreshRequestError : McpHeadersHandlePendingHeadersRefreshRequest +{ + /// + [JsonIgnore] + public override string Kind => "error"; + + /// Host credential broker failure, denial, or revocation reason. + [JsonPropertyName("message")] + public required string Message { get; set; } +} + +/// MCP headers refresh request id and the host response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpHeadersHandlePendingHeadersRefreshRequestRequest +{ + /// Headers refresh request identifier from mcp.headers_refresh_required. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Host response: supply dynamic headers or decline this refresh. + [JsonPropertyName("result")] + public McpHeadersHandlePendingHeadersRefreshRequest Result { get => field ??= new(); set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsResourceContent +{ + /// Resource-level metadata (CSP, permissions, etc.). + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Base64-encoded binary content. + [JsonPropertyName("blob")] + public string? Blob { get; set; } + + /// MIME type of the content. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Text content (e.g. HTML). + [JsonPropertyName("text")] + public string? Text { get; set; } + + /// The resource URI (typically ui://...). + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; +} + +/// Resource contents returned by the MCP server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsReadResourceResult +{ + /// Resource contents returned by the server. + [JsonPropertyName("contents")] + public IList Contents { get => field ??= []; set; } +} + +/// MCP server and resource URI to fetch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpAppsReadResourceRequest +{ + /// Name of the MCP server hosting the resource. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Resource URI (typically ui://...). + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; +} + +/// App-callable tools from the named MCP server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsListToolsResult +{ + /// App-callable tools from the server. + [JsonPropertyName("tools")] + public IList> Tools { get => field ??= []; set; } +} + +/// MCP server to list app-callable tools for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpAppsListToolsRequest +{ + /// **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. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("originServerName")] + public string OriginServerName { get; set; } = string.Empty; + + /// MCP server hosting the app. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// MCP server, tool name, and arguments to invoke from an MCP App view. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpAppsCallToolRequest +{ + /// Tool arguments. + [JsonPropertyName("arguments")] + public IDictionary? Arguments { get; set; } + + /// **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. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("originServerName")] + public string OriginServerName { get; set; } = string.Empty; + + /// MCP server hosting the tool. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// MCP tool name. + [JsonPropertyName("toolName")] + public string ToolName { get; set; } = string.Empty; +} + +/// Host context advertised to MCP App guests. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsSetHostContextDetails +{ + /// Display modes the host supports. + [JsonPropertyName("availableDisplayModes")] + public IList? AvailableDisplayModes { get; set; } + + /// Current display mode (SEP-1865). + [JsonPropertyName("displayMode")] + public McpAppsSetHostContextDetailsDisplayMode? DisplayMode { get; set; } + + /// BCP-47 locale, e.g. 'en-US'. + [JsonPropertyName("locale")] + public string? Locale { get; set; } + + /// Platform type for responsive design. + [JsonPropertyName("platform")] + public McpAppsSetHostContextDetailsPlatform? Platform { get; set; } + + /// UI theme preference per SEP-1865. + [JsonPropertyName("theme")] + public McpAppsSetHostContextDetailsTheme? Theme { get; set; } + + /// IANA timezone, e.g. 'America/New_York'. + [JsonPropertyName("timeZone")] + public string? TimeZone { get; set; } + + /// Host application identifier. + [JsonPropertyName("userAgent")] + public string? UserAgent { get; set; } +} + +/// Host context to advertise to MCP App guests. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpAppsSetHostContextRequest +{ + /// Host context advertised to MCP App guests. + [JsonPropertyName("context")] + public McpAppsSetHostContextDetails Context { get => field ??= new(); set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Current host context. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsHostContextDetails +{ + /// Display modes the host supports. + [JsonPropertyName("availableDisplayModes")] + public IList? AvailableDisplayModes { get; set; } + + /// Current display mode (SEP-1865). + [JsonPropertyName("displayMode")] + public McpAppsHostContextDetailsDisplayMode? DisplayMode { get; set; } + + /// BCP-47 locale, e.g. 'en-US'. + [JsonPropertyName("locale")] + public string? Locale { get; set; } + + /// Platform type for responsive design. + [JsonPropertyName("platform")] + public McpAppsHostContextDetailsPlatform? Platform { get; set; } + + /// UI theme preference per SEP-1865. + [JsonPropertyName("theme")] + public McpAppsHostContextDetailsTheme? Theme { get; set; } + + /// IANA timezone, e.g. 'America/New_York'. + [JsonPropertyName("timeZone")] + public string? TimeZone { get; set; } + + /// Host application identifier. + [JsonPropertyName("userAgent")] + public string? UserAgent { get; set; } +} + +/// Current host context advertised to MCP App guests. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsHostContext +{ + /// Current host context. + [JsonPropertyName("context")] + public McpAppsHostContextDetails Context { get => field ??= new(); set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpAppsGetHostContextRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Capability negotiation snapshot. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsDiagnoseCapability +{ + /// Whether the runtime advertises `extensions.io.modelcontextprotocol/ui` to MCP servers. + [JsonPropertyName("advertised")] + public bool Advertised { get; set; } + + /// Whether the MCP_APPS feature flag (or COPILOT_MCP_APPS env override) is on. + [JsonPropertyName("featureFlagEnabled")] + public bool FeatureFlagEnabled { get; set; } + + /// Whether the session has the `mcp-apps` capability. + [JsonPropertyName("sessionHasMcpApps")] + public bool SessionHasMcpApps { get; set; } +} + +/// What the server returned for this session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsDiagnoseServer +{ + /// Whether the named server is currently connected. + [JsonPropertyName("connected")] + public bool Connected { get; set; } + + /// Up to 5 tool names with `_meta.ui` for quick inspection. + [JsonPropertyName("sampleToolNames")] + public IList SampleToolNames { get => field ??= []; set; } + + /// Total tools returned by the server's tools/list. + [JsonPropertyName("toolCount")] + public double ToolCount { get; set; } + + /// Tools whose `_meta.ui` is populated (resourceUri and/or visibility set). + [JsonPropertyName("toolsWithUiMeta")] + public double ToolsWithUiMeta { get; set; } +} + +/// Diagnostic snapshot of MCP Apps wiring for the named server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpAppsDiagnoseResult +{ + /// Capability negotiation snapshot. + [JsonPropertyName("capability")] + public McpAppsDiagnoseCapability Capability { get => field ??= new(); set; } + + /// What the server returned for this session. + [JsonPropertyName("server")] + public McpAppsDiagnoseServer Server { get => field ??= new(); set; } +} + +/// MCP server to diagnose MCP Apps wiring for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpAppsDiagnoseRequest +{ + /// MCP server to probe. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// MCP resource content with URI, optional MIME type, text or base64 blob, and resource metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResourceContent +{ + /// Resource-level metadata (CSP, permissions, etc.). + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Base64-encoded binary content. + [JsonPropertyName("blob")] + public string? Blob { get; set; } + + /// MIME type of the content. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Text content (e.g. HTML). + [JsonPropertyName("text")] + public string? Text { get; set; } + + /// The resource URI. + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; +} + +/// Resource contents returned by the MCP server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResourcesReadResult +{ + /// Resource contents returned by the server. + [JsonPropertyName("contents")] + public IList Contents { get => field ??= []; set; } +} + +/// MCP server and resource URI to fetch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpResourcesReadRequest +{ + /// Name of the MCP server hosting the resource. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Resource URI. + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; +} + +/// Standard MCP resource annotations plus preserved non-standard annotation fields. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResourceAnnotations +{ + /// Server-provided non-standard annotation fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Intended audience roles for this resource. + [JsonPropertyName("audience")] + public IList? Audience { get; set; } + + /// Last-modified timestamp hint. + [JsonPropertyName("lastModified")] + public string? LastModified { get; set; } + + /// Priority hint for model/client use. + [JsonPropertyName("priority")] + public double? Priority { get; set; } +} + +/// A resource icon descriptor plus preserved non-standard icon fields. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResourceIcon +{ + /// Server-provided non-standard icon fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Icon MIME type, when known. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Icon sizes hint. + [JsonPropertyName("sizes")] + public string? Sizes { get; set; } + + /// Icon URI. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; + + /// Theme hint for this icon. + [JsonPropertyName("theme")] + public string? Theme { get; set; } +} + +/// An MCP resource descriptor (spec `Resource`): URI, name, and optional title, description, MIME type, size, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResource +{ + /// Resource-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard descriptor fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Model/client annotations associated with this resource. + [JsonPropertyName("annotations")] + public McpResourceAnnotations? Annotations { get; set; } + + /// Optional description of what this resource represents. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Icons associated with this resource. + [JsonPropertyName("icons")] + public IList? Icons { get; set; } + + /// MIME type of the resource, if known. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// The programmatic name of the resource. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Resource size in bytes, when known. + [JsonPropertyName("size")] + public long? Size { get; set; } + + /// Optional human-readable display title. + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// The resource URI (e.g. ui://... or file:///...). + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; +} + +/// One page of resources advertised by the named MCP server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResourcesListResult +{ + /// Opaque cursor for the next page, if the server has more resources. + [JsonPropertyName("nextCursor")] + public string? NextCursor { get; set; } + + /// Resources advertised by the server (proxied MCP `resources/list`). + [JsonPropertyName("resources")] + public IList Resources { get => field ??= []; set; } +} + +/// MCP server whose resources to enumerate. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpResourcesListRequest +{ + /// Opaque MCP pagination cursor from a prior `nextCursor` value. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Name of the MCP server whose resources to enumerate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// An MCP resource template descriptor (spec `ResourceTemplate`): an RFC 6570 URI template, name, and optional title, description, MIME type, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResourceTemplate +{ + /// Resource-template-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard descriptor fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Model/client annotations associated with this template. + [JsonPropertyName("annotations")] + public McpResourceAnnotations? Annotations { get; set; } + + /// Optional description of what this template is for. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Icons associated with resources matching this template. + [JsonPropertyName("icons")] + public IList? Icons { get; set; } + + /// MIME type for resources matching this template, if uniform. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// The programmatic name of the resource template. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Optional human-readable display title. + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// An RFC 6570 URI template for constructing resource URIs. + [JsonPropertyName("uriTemplate")] + public string UriTemplate { get; set; } = string.Empty; +} + +/// One page of resource templates advertised by the named MCP server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpResourcesListTemplatesResult +{ + /// Opaque cursor for the next page, if the server has more resource templates. + [JsonPropertyName("nextCursor")] + public string? NextCursor { get; set; } + + /// Resource templates advertised by the server (proxied MCP `resources/templates/list`). + [JsonPropertyName("resourceTemplates")] + public IList ResourceTemplates { get => field ??= []; set; } +} + +/// MCP server whose resource templates to enumerate. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpResourcesListTemplatesRequest +{ + /// Opaque MCP pagination cursor from a prior `nextCursor` value. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Name of the MCP server whose resource templates to enumerate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// An argument accepted by an MCP prompt. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPromptArgument +{ + /// Argument-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard argument fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Description of the argument. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Name of the argument. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Whether the argument is required; omission is distinct from false. + [JsonPropertyName("required")] + public bool? Required { get; set; } +} + +/// An MCP prompt icon with standard size hints and preserved non-standard fields. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPromptIcon +{ + /// Server-provided non-standard icon fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Icon MIME type, when known. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Icon sizes, such as `48x48` or `any`. + [JsonPropertyName("sizes")] + public IList? Sizes { get; set; } + + /// Icon URI. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; + + /// Theme hint for this icon. + [JsonPropertyName("theme")] + public string? Theme { get; set; } +} + +/// An MCP prompt descriptor. Server-provided non-standard fields are exposed under `additionalProperties`. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPrompt +{ + /// Prompt-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard descriptor fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Arguments accepted by the prompt. + [JsonPropertyName("arguments")] + public IList? Arguments { get; set; } + + /// Description of what this prompt provides. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Icons associated with this prompt. + [JsonPropertyName("icons")] + public IList? Icons { get; set; } + + /// The programmatic name of the prompt. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Human-readable display title. + [JsonPropertyName("title")] + public string? Title { get; set; } +} + +/// One page of prompts advertised by the named MCP server. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPromptsListResult +{ + /// MCP result metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard result fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Opaque cursor for the next page, if the server has more prompts. + [JsonPropertyName("nextCursor")] + public string? NextCursor { get; set; } + + /// Prompts advertised by the server. + [JsonPropertyName("prompts")] + public IList Prompts { get => field ??= []; set; } +} + +/// MCP server whose prompts to enumerate. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpPromptsListRequest +{ + /// Opaque MCP pagination cursor from a prior `nextCursor` value. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Name of the MCP server whose prompts to enumerate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// An MCP prompt message with opaque JSON content preserved without flattening or content-type filtering. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPromptMessage +{ + /// Message-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard message fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// The original MCP content block, including nested metadata and unfamiliar content types. + [JsonPropertyName("content")] + public JsonElement Content { get; set; } + + /// The role of the message sender. + [JsonPropertyName("role")] + public McpPromptRole Role { get; set; } +} + +/// Prompt messages returned by the MCP server without sending them to the model. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPromptsGetResult +{ + /// MCP result metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard result fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Description of the prompt. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Ordered prompt messages. + [JsonPropertyName("messages")] + public IList Messages { get => field ??= []; set; } +} + +/// MCP server, prompt name, and optional string-valued arguments. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpPromptsGetRequest +{ + /// String-valued arguments to pass to the prompt. + [JsonPropertyName("arguments")] + public IDictionary? Arguments { get; set; } + + /// The programmatic name of the prompt. + [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("promptName")] + public string PromptName { get; set; } = string.Empty; + + /// Name of the MCP server hosting the prompt. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [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("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// MCP diagnostic source configuration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpDiagnosticSourceConfiguration +{ + /// Threshold to apply to MCP diagnostic producers in this session. + [JsonPropertyName("level")] + public DiagnosticLogLevel Level { get; set; } +} + +/// Typed diagnostic source configuration. At least one source is required by diagnostics configuration methods. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiagnosticSourcesConfiguration +{ + /// MCP diagnostic capture threshold. Omit to leave the current threshold unchanged. + [JsonPropertyName("mcp")] + public McpDiagnosticSourceConfiguration? Mcp { get; set; } +} + +/// Per-source session diagnostics configuration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiagnosticsConfiguration +{ + /// Diagnostic thresholds keyed by supported source. + [JsonPropertyName("sources")] + public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } +} + +/// Patch session diagnostic thresholds for explicitly supplied sources. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class DiagnosticsConfigureRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Sources to configure. At least one supported source must be supplied. + [JsonPropertyName("sources")] + public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } +} + +/// One retained session-scoped diagnostic record. Potentially content-bearing diagnostic data is opt-in and must not be exported automatically as telemetry. +/// Polymorphic base type discriminated by source. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "source", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(DiagnosticEntryMcp), "mcp")] +public partial class DiagnosticEntry +{ + /// The type discriminator. + [JsonPropertyName("source")] + public virtual string Source { get; set; } = string.Empty; +} + + +/// MCP-specific detail for a source-discriminated diagnostic entry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpDiagnosticDetails +{ + /// Fresh identifier for the MCP connection attempt, including failed starts. + [JsonPropertyName("connectionId")] + public string ConnectionId { get; set; } = string.Empty; + + /// Serialized diagnostic detail. Protocol and HTTP records use JSON when detail is present. + [JsonPropertyName("data")] + public string? Data { get; set; } + + /// Protocol-frame direction when kind is protocol. + [JsonPropertyName("direction")] + public McpDiagnosticDirection? Direction { get; set; } + + /// Diagnostic record category. + [JsonPropertyName("kind")] + public McpDiagnosticKind Kind { get; set; } + + /// Configured MCP server name. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; +} + +/// The mcp variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class DiagnosticEntryMcp : DiagnosticEntry +{ + /// + [JsonIgnore] + public override string Source => "mcp"; + + /// Agent identifier for a subagent host. Omitted for the root agent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("agentId")] + public string? AgentId { get; set; } + + /// Typed MCP diagnostic detail. + [JsonPropertyName("details")] + public required McpDiagnosticDetails Details { get; set; } + + /// Severity of this emitted diagnostic record. + [JsonPropertyName("level")] + public required DiagnosticSeverity Level { get; set; } + + /// Human-readable diagnostic summary. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Original byte count when a known-size message or data value was truncated. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("originalBytes")] + public long? OriginalBytes { get; set; } + + /// UTC RFC 3339 timestamp captured at the diagnostic source. + [JsonPropertyName("timestamp")] + public required string Timestamp { get; set; } + + /// Whether message or data was truncated to the record-size bound. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("truncated")] + public bool? Truncated { get; set; } +} + +/// One cursor-addressed page of retained session diagnostics. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiagnosticsReadResult +{ + /// Opaque cursor for the next independent read. + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; + + /// Whether the requested cursor remained within the retained buffer window. + [JsonPropertyName("cursorStatus")] + public DiagnosticCursorStatus CursorStatus { get; set; } + + /// Number of records lost before this page when known. Omitted when a buffer generation change makes the count unknowable. + [JsonPropertyName("droppedCount")] + public long? DroppedCount { get; set; } + + /// Retained records beginning at the requested cursor. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } + + /// Whether additional retained records follow this page. + [JsonPropertyName("hasMore")] + public bool HasMore { get; set; } +} + +/// Cursor-based request for session diagnostics. The default limit is 100 (maximum 500); the default waitMs is zero (maximum 30000). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class DiagnosticsReadRequest +{ + /// Opaque cursor returned by an earlier read. Omit to start at the oldest retained record. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Maximum number of records to return, from 1 through 500. Omit for 100. + [JsonPropertyName("max")] + public long? Max { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Nonempty selection of sources to read. Each source may be listed once. + [JsonPropertyName("sources")] + public IList Sources { get => field ??= []; set; } + + /// Maximum time in milliseconds to wait for a new record, from 0 through 30000. + [JsonPropertyName("waitMs")] + public int? WaitMs { get; set; } +} + +/// Feature detection and hard polling limits for the EXPERIMENTAL session connector API. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorCapabilities +{ + /// Connector API contract version. + [JsonPropertyName("apiVersion")] + public long ApiVersion { get; set; } + + /// Current session availability. Disabled availability is reported without making a Connector request. + [JsonPropertyName("availability")] + public ConnectorAvailability Availability { get; set; } + + /// Whether connect and reconnect can return an opaque continuation for bounded consent polling. + [JsonPropertyName("consentContinuation")] + public bool ConsentContinuation { get; set; } + + /// Maximum accepted wall-clock deadline in milliseconds for one continuation call. + [JsonPropertyName("maxDeadlineMs")] + public long MaxDeadlineMs { get; set; } + + /// Maximum accepted polling attempts for one continuation call. + [JsonPropertyName("maxPollAttempts")] + public long MaxPollAttempts { get; set; } + + /// Maximum accepted delay in milliseconds between polling attempts. + [JsonPropertyName("maxPollIntervalMs")] + public long MaxPollIntervalMs { get; set; } + + /// Whether callers select a host-owned GitHub account through an opaque selection ID rather than supplying a provider token. + [JsonPropertyName("opaqueAccountSelection")] + public bool OpaqueAccountSelection { get; set; } + + /// Whether getAccount is supported. Absence means false. + [JsonPropertyName("sessionAccountSelection")] + public bool? SessionAccountSelection { get; set; } + + /// Whether reconcile accepts forceConnectorName. Absence means false. + [JsonPropertyName("targetedReconcile")] + public bool? TargetedReconcile { get; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsGetCapabilitiesRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Credential-free identity metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AuthIdentityMetadata +{ + /// Identity host. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// User login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; + + /// Authentication type. + [JsonPropertyName("type")] + public AuthInfoType Type { get; set; } +} + +/// Session account selection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorSessionAccount +{ + /// Opaque session-scoped account selection ID. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Credential-free identity metadata. + [JsonPropertyName("authInfo")] + public AuthIdentityMetadata AuthInfo { get => field ??= new(); set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsGetAccountRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Account-targeted authorization update required by the Connector service. The account ID is an opaque host routing identifier; no credential is included. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorAuthorizationRequirement +{ + /// Exact opaque account selection that made the Connector request. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Stable OAuth scope the selected account must grant. + [JsonPropertyName("scope")] + public ConnectorAuthorizationScope Scope { get; set; } +} + +/// Credential-free Connector catalog entry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorCatalogEntry +{ + /// Untrusted service description, when present. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Untrusted display label from the service. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + /// Optional catalog logo. + [JsonPropertyName("logo")] + public string? Logo { get; set; } + + /// Canonical Connector name used by lifecycle methods. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Optional catalog release tag. + [JsonPropertyName("releaseTag")] + public string? ReleaseTag { get; set; } + + /// Opaque stable runtime IDs currently projected into the session for this Connector. + [JsonPropertyName("runtimeServerIds")] + public IList RuntimeServerIds { get => field ??= []; set; } + + /// Current authoritative service connection state. + [JsonPropertyName("status")] + public ConnectorCatalogStatus Status { get; set; } + + /// Optional catalog tier. + [JsonPropertyName("tier")] + public string? Tier { get; set; } +} + +/// Validated Connector catalog snapshot cached by the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorCatalogResult +{ + /// Validated catalog entries in service order. + [JsonPropertyName("connectors")] + public IList Connectors { get => field ??= []; set; } + + /// Unix epoch milliseconds when this snapshot was accepted. + [JsonPropertyName("refreshedAtMs")] + public long RefreshedAtMs { get; set; } + + /// Monotonically increasing session-local catalog revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } +} + +/// Live status of one session-owned MCP projection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorRuntimeStatus +{ + /// Canonical Connector name that owns this server. + [JsonPropertyName("connectorName")] + public string ConnectorName { get; set; } = string.Empty; + + /// Opaque runtime server ID. + [JsonPropertyName("runtimeServerId")] + public string RuntimeServerId { get; set; } = string.Empty; + + /// Current live MCP host status. + [JsonPropertyName("status")] + public ConnectorMcpStatus Status { get; set; } +} + +/// Authoritative session connector state. Account IDs are opaque routing identifiers and credentials are never included. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorStatus +{ + /// Opaque account selection pinned to this session, when one has been selected. + [JsonPropertyName("accountId")] + public string? AccountId { get; set; } + + /// Connector API contract version. + [JsonPropertyName("apiVersion")] + public long ApiVersion { get; set; } + + /// Exact selected account and stable scope requiring an authorization update, when proven by the Connector service. + [JsonPropertyName("authorizationRequirement")] + public ConnectorAuthorizationRequirement? AuthorizationRequirement { get; set; } + + /// Current feature and session availability. + [JsonPropertyName("availability")] + public ConnectorAvailability Availability { get; set; } + + /// Latest validated catalog snapshot, when available. + [JsonPropertyName("catalog")] + public ConnectorCatalogResult? Catalog { get; set; } + + /// Number of active opaque connection continuations. + [JsonPropertyName("pendingConnections")] + public long PendingConnections { get; set; } + + /// Live MCP status for every Connector-owned runtime server. + [JsonPropertyName("runtimeServers")] + public IList RuntimeServers { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsGetStatusRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Pins a Connector operation to one host-owned GitHub account through its opaque selection ID. Provider tokens are never accepted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorAccountRequest +{ + /// Opaque account selection ID previously returned by an account discovery API. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Typed result of initiating or continuing a Connector connection. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(ConnectorConnectResultConnected), "connected")] +[JsonDerivedType(typeof(ConnectorConnectResultConsentRequired), "consent_required")] +[JsonDerivedType(typeof(ConnectorConnectResultPending), "pending")] +public partial class ConnectorConnectResult +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} + + +/// The service is connected and the session MCP graph was reconciled. +/// The connected variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ConnectorConnectResultConnected : ConnectorConnectResult +{ + /// + [JsonIgnore] + public override string Kind => "connected"; + + /// Fresh authoritative Connector state after MCP reconciliation. + [JsonPropertyName("status")] + public required ConnectorStatus Status { get; set; } +} + +/// Host-owned consent is required before bounded continuation can complete. +/// The consent_required variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ConnectorConnectResultConsentRequired : ConnectorConnectResult +{ + /// + [JsonIgnore] + public override string Kind => "consent_required"; + + /// Validated HTTPS consent URL. The runtime does not open it. + [JsonPropertyName("consentUrl")] + public required string ConsentUrl { get; set; } + + /// Opaque ID accepted by continueConnection. + [JsonPropertyName("continuationId")] + public required string ContinuationId { get; set; } +} + +/// The service is still completing the connection without a consent URL. +/// The pending variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ConnectorConnectResultPending : ConnectorConnectResult +{ + /// + [JsonIgnore] + public override string Kind => "pending"; + + /// Opaque ID accepted by continueConnection. + [JsonPropertyName("continuationId")] + public required string ContinuationId { get; set; } +} + +/// Selects one Connector and the pinned host-owned account used for its service and MCP authorization. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorConnectRequest +{ + /// Opaque account selection ID. It must match the account already pinned to the session, if any. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Canonical Connector name from the current catalog. + [JsonPropertyName("connectorName")] + public string ConnectorName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Explicitly bounded continuation of a pending Connector connection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorContinueRequest +{ + /// Opaque continuation ID returned by connect, reconnect, or an earlier continuation. + [JsonPropertyName("continuationId")] + public string ContinuationId { get; set; } = string.Empty; + + /// Maximum wall-clock duration in milliseconds for this call. Must be between one and the capability limit. + [JsonPropertyName("deadlineMs")] + public int DeadlineMs { get; set; } + + /// Maximum catalog requests made by this call. Must be between one and the capability limit. + [JsonPropertyName("maxAttempts")] + public int MaxAttempts { get; set; } + + /// Delay in milliseconds between attempts. Must not exceed the capability limit. + [JsonPropertyName("pollIntervalMs")] + public int PollIntervalMs { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Authoritative result after disconnect and MCP reconciliation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDisconnectResult +{ + /// Whether the service accepted the idempotent disconnect. + [JsonPropertyName("disconnected")] + public bool Disconnected { get; set; } + + /// Fresh authoritative session state after removing Connector-owned MCP servers. + [JsonPropertyName("status")] + public ConnectorStatus Status { get => field ??= new(); set; } +} + +/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorReconcileRequest +{ + /// Opaque account selection ID. It must match the account already pinned to the session, if any. + [JsonPropertyName("accountId")] + public required string AccountId { get; set; } + + /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. + [JsonPropertyName("forceConnectorName")] + public string? ForceConnectorName { get; set; } + + /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. + [JsonPropertyName("refreshCatalog")] + public bool? RefreshCatalog { get; set; } +} + +/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorReconcileRequestWithSession +{ + /// Opaque account selection ID. It must match the account already pinned to the session, if any. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. + [JsonPropertyName("forceConnectorName")] + public string? ForceConnectorName { get; set; } + + /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. + [JsonPropertyName("refreshCatalog")] + public bool? RefreshCatalog { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsWithdrawProjectionRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionManagedSettingsGetRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Session plugin metadata, with name, marketplace, optional version, and enabled state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class Plugin +{ + /// Opaque stable identity for a direct plugin source. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } + + /// Whether the plugin is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Whether this managed desired plugin has an installed or live record. + [JsonPropertyName("installed")] + public bool? Installed { get; set; } + + /// Absolute marketplace directory for a live plugin. + [JsonPropertyName("installedFrom")] + public string? InstalledFrom { get; set; } + + /// Whether enterprise managed settings control this plugin. + [JsonPropertyName("managed")] + public bool? Managed { get; set; } + + /// Enabled state required by enterprise managed settings. + [JsonPropertyName("managedDesiredEnabled")] + public bool? ManagedDesiredEnabled { get; set; } + + /// Marketplace the plugin came from. + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Runtime plugin provenance, such as "builtin". + [JsonPropertyName("source")] + public string? Source { get; set; } + + /// Installed version. + [JsonPropertyName("version")] + public string? Version { get; set; } +} + +/// Plugins installed for the session, with their enabled state and version metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PluginList +{ + /// Installed plugins. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Plugin source resolved relative to the session's authoritative working directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsInstallRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; +} + +/// Name (or spec) of the plugin to uninstall. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsUninstallRequestWithSession +{ + /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } + + /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name (or spec) of the plugin to update. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsUpdateRequestWithSession +{ + /// Plugin name or "plugin@marketplace" spec to update. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Plugin names (or specs) to enable in the session's authoritative working directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsEnableRequest +{ + /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Plugin names (or specs) to disable in the session's authoritative working directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsDisableRequest +{ + /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// RPC data type for SessionPluginsReload operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsReloadRequest +{ + /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. + [JsonPropertyName("deferRepoHooks")] + public bool? DeferRepoHooks { get; set; } + + /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadCustomAgents")] + public bool? ReloadCustomAgents { get; set; } + + /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). + [JsonPropertyName("reloadExtensions")] + public bool? ReloadExtensions { get; set; } + + /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). + [JsonPropertyName("reloadHooks")] + public bool? ReloadHooks { get; set; } + + /// Reload MCP server connections after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadMcp")] + public bool? ReloadMcp { get; set; } +} + +/// RPC data type for SessionPluginsReloadRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsReloadRequestWithSession +{ + /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. + [JsonPropertyName("deferRepoHooks")] + public bool? DeferRepoHooks { get; set; } + + /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadCustomAgents")] + public bool? ReloadCustomAgents { get; set; } + + /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). + [JsonPropertyName("reloadExtensions")] + public bool? ReloadExtensions { get; set; } + + /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). + [JsonPropertyName("reloadHooks")] + public bool? ReloadHooks { get; set; } + + /// Reload MCP server connections after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadMcp")] + public bool? ReloadMcp { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Retry outcome for one plugin required by managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedPluginRetryEntry +{ + /// Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Plugin spec in "plugin@marketplace" form. + [JsonPropertyName("spec")] + public string Spec { get; set; } = string.Empty; + + /// What the retry did for this plugin. + [JsonPropertyName("status")] + public ManagedPluginRetryStatus Status { get; set; } +} + +/// Per-plugin outcomes of retrying the plugins required by the session's managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsRetryManagedResult +{ + /// One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } +} + +/// RPC data type for SessionPluginsRetryManaged operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsRetryManagedRequest +{ + /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + [JsonPropertyName("plugins")] + public IList? Plugins { get; set; } +} + +/// RPC data type for SessionPluginsRetryManagedRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsRetryManagedRequestWithSession +{ + /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + [JsonPropertyName("plugins")] + public IList? Plugins { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsMarketplacesListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Marketplace source and optional working directory for relative-path resolution. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesAddRequestWithSession +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; + + /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} + +/// Name of the marketplace to remove and an optional force flag. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesRemoveRequestWithSession +{ + /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. + [JsonPropertyName("force")] + public bool? Force { get; set; } + + /// Marketplace name to remove. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name of the marketplace whose plugin catalog to fetch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesBrowseRequestWithSession +{ + /// Marketplace name to browse. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// RPC data type for SessionPluginsMarketplacesRefresh operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsMarketplacesRefreshRequest +{ + /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + [JsonPropertyName("name")] + public string? Name { get; set; } +} + +/// RPC data type for SessionPluginsMarketplacesRefreshRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsMarketplacesRefreshRequestWithSession +{ + /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderSessionToken +{ + /// When the token expires, if known. Callers should refresh by calling `getEndpoint` again before this time, or reactively on any 401/403 response from `baseUrl`. + [JsonPropertyName("expiresAt")] + public DateTimeOffset? ExpiresAt { get; set; } + + /// HTTP header name the token must be sent under. + [JsonPropertyName("header")] + public string Header { get; set; } = string.Empty; + + /// The model the token is bound to, when applicable. When set, the token is only valid for requests against this model. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// The short-lived token value. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; +} + +/// A snapshot of the provider endpoint the session is currently configured to talk to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderEndpoint +{ + /// A credential the caller should use with this endpoint. Omitted only when the endpoint accepts unauthenticated requests. + [JsonPropertyName("apiKey")] + public string? ApiKey { get; set; } + + /// Base URL to pass to the LLM client library. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("baseUrl")] + public string BaseUrl { get; set; } = string.Empty; + + /// HTTP headers the caller must include on every outbound request. + [JsonPropertyName("headers")] + public IDictionary Headers { get => field ??= new Dictionary(); set; } + + /// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. + [JsonPropertyName("sessionToken")] + public ProviderSessionToken? SessionToken { get; set; } + + /// Transport to be used for provider requests. + [JsonPropertyName("transport")] + public ProviderEndpointTransport? Transport { get; set; } + + /// Provider family. Matches the `type` field of a BYOK provider config. + [JsonPropertyName("type")] + public ProviderEndpointType Type { get; set; } + + /// Wire API to be used, when required for the provider type. + [JsonPropertyName("wireApi")] + public ProviderEndpointWireApi? WireApi { get; set; } +} + +/// RPC data type for SessionProviderGetEndpoint operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionProviderGetEndpointRequest +{ + /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } +} + +/// RPC data type for SessionProviderGetEndpointRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionProviderGetEndpointRequestWithSession +{ + /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The selectable model entries synthesized for the models added by this call. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderAddResult +{ + /// Synthesized selectable model entries for the newly added BYOK models, each under its provider-qualified selection id (`provider/id`). Empty when only providers were added. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } +} + +/// BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ProviderAddRequest +{ + /// BYOK model definitions to register. Each must reference a provider that is already registered or included in this same call. Selection ids (`provider/id`) must be unique across the registry. + [JsonPropertyName("models")] + public IList? Models { get; set; } + + /// Named BYOK provider connections to register, additive to any providers already in the registry. Each name must be unique across the registry and must not contain '/'. + [JsonPropertyName("providers")] + public IList? Providers { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The selectable model entries and selection ids synthesized for the synchronized BYOK models. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderSyncResult +{ + /// True when synchronization withdrew the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Synchronization never promotes a surviving host model in its place: publishing a model offers it, and the choice of which model to use stays with the user. + [JsonPropertyName("modelDeselected")] + public bool? ModelDeselected { get; set; } + + /// Synthesized selectable model entries for the synchronized BYOK models. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } + + /// Provider-qualified model selection ids present after synchronization. + [JsonPropertyName("selectionIds")] + public IList SelectionIds { get => field ??= []; set; } +} + +/// Authoritative BYOK provider and model registry snapshot to apply atomically to the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ProviderSyncRequest +{ + /// BYOK model definition snapshot. Models absent from this list are removed. + [JsonPropertyName("models")] + public IList? Models { get; set; } + + /// Named BYOK provider connection snapshot. Providers absent from this list are removed. + [JsonPropertyName("providers")] + public IList? Providers { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// What the withdrawal actually removed from the registry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderWithdrawResult +{ + /// True when withdrawal removed the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Withdrawal never promotes a surviving model in its place: the choice of which model to use stays with the user. + [JsonPropertyName("modelDeselected")] + public bool? ModelDeselected { get; set; } + + /// Providers removed because one of the withdrawn models was the last entry referencing them. A provider that merely has no models is not removed. + [JsonPropertyName("providersRemoved")] + public IList ProvidersRemoved { get => field ??= []; set; } + + /// Selection ids that were registered and are now withdrawn. Excludes requested ids that were not present. + [JsonPropertyName("withdrawn")] + public IList Withdrawn { get => field ??= []; set; } +} + +/// Host-managed model selection ids to withdraw from the session's BYOK registry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ProviderWithdrawRequest +{ + /// Provider-qualified selection ids to withdraw. Ids that are not registered are ignored, so withdrawal is idempotent. A provider left with no models referencing it is removed too. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the session options patch was applied successfully. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionUpdateOptionsResult +{ + /// Number of hooks loaded from installed plugins, returned when installedPlugins is updated. + [JsonPropertyName("pluginHookCount")] + public long? PluginHookCount { get; set; } + + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class OptionsUpdateAdditionalContentExclusionPolicyRuleSource +{ + /// Name of the policy source. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Type of the policy source. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; +} + +/// Single content-exclusion rule supplied to `session.options.update`, with paths, match conditions, and source. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class OptionsUpdateAdditionalContentExclusionPolicyRule +{ + /// Conditions of which at least one must match. + [JsonPropertyName("ifAnyMatch")] + public IList? IfAnyMatch { get; set; } + + /// Conditions none of which may match. + [JsonPropertyName("ifNoneMatch")] + public IList? IfNoneMatch { get; set; } + + /// Path patterns covered by this rule. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } + + /// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. + [JsonPropertyName("source")] + public OptionsUpdateAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } +} + +/// Content-exclusion policy supplied to `session.options.update`, with rules, last-updated data, and scope. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class OptionsUpdateAdditionalContentExclusionPolicy +{ + /// Opaque policy update timestamp supplied by the host. + [JsonPropertyName("last_updated_at")] + public JsonElement LastUpdatedAt { get; set; } + + /// Content-exclusion rules to apply. + [JsonPropertyName("rules")] + public IList Rules { get => field ??= []; set; } + + /// Allowed values for the `OptionsUpdateAdditionalContentExclusionPolicyScope` enumeration. + [JsonPropertyName("scope")] + public OptionsUpdateAdditionalContentExclusionPolicyScope Scope { get; set; } +} + +/// Options scoped to the built-in CAPI (Copilot API) provider. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CapiSessionOptions +{ + /// Routing preference for sessions whose model is `auto`. On create or cold resume, this establishes the preference sent as `tier` on CAPI `/auto` requests; when omitted on cold resume, the runtime restores the last committed preference. On resident resume, a different value requests a safe switch after resume succeeds and cannot change an in-flight turn. Successful switches are persisted for later cold resume. When no preference is supplied or restored, CAPI default routing is used. `fast` is an integrator-only latency preset, not a first-party GitHub Copilot product preference. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } + + /// Whether to use WebSocket transport for the CAPI Responses API. Enabled by default when the model advertises `ws:/responses` support; set to `false` to force the HTTP Responses transport in environments where WebSockets are blocked (e.g. behind a proxy). Setting this to `false` is equivalent to the `COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES` environment variable. + [JsonPropertyName("enableWebSocketResponses")] + public bool? EnableWebSocketResponses { get; set; } +} + +/// Installed plugin record for a session, with marketplace, version, install time, enabled state, cache path, and source. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionInstalledPlugin +{ + /// Path where the plugin is cached locally. + [JsonPropertyName("cache_path")] + public string? CachePath { get; set; } + + /// Whether the plugin is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Installation timestamp (ISO-8601). + [JsonPropertyName("installed_at")] + public string InstalledAt { get; set; } = string.Empty; + + /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. + [JsonPropertyName("installed_from")] + public string? InstalledFrom { get; set; } + + /// Marketplace the plugin came from (empty string for direct repo installs). + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Source descriptor for direct repo installs (when marketplace is empty). + [JsonPropertyName("source")] + public JsonElement? Source { get; set; } + + /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. + [JsonPropertyName("source_sha")] + public string? SourceSha { get; set; } + + /// Installed version, if known. + [JsonPropertyName("version")] + public string? Version { get; set; } +} + +/// Custom model-provider configuration (BYOK). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderConfig +{ + /// API key. Optional for local providers like Ollama. + [JsonPropertyName("apiKey")] + public string? ApiKey { get; set; } + + /// Azure-specific provider options. + [JsonPropertyName("azure")] + public ProviderConfigAzure? Azure { get; set; } + + /// API endpoint URL. + [JsonPropertyName("baseUrl")] + public string BaseUrl { get; set; } = string.Empty; + + /// Bearer token for authentication. Sets the Authorization header directly. Takes precedence over apiKey when both are set. + [JsonPropertyName("bearerToken")] + public string? BearerToken { get; set; } + + /// When true, the SDK client supplies bearer tokens on demand: the runtime calls the client-session `providerToken.getToken` callback before each request and applies the returned token as an `Authorization: Bearer <token>` header. This is the bearer/OAuth scheme used by Azure AD / managed-identity tokens and provider OAuth access tokens (including Anthropic's), not a provider-specific API-key header such as Anthropic's `x-api-key`. The token-acquiring function itself stays on the SDK side and is never serialized; only this flag crosses the wire. When set alongside `apiKey`/`bearerToken`, the callback takes precedence: the runtime applies the token returned by `providerToken.getToken` as the `Authorization: Bearer` header for each request and does not send the static credential. + [JsonPropertyName("hasBearerTokenProvider")] + public bool? HasBearerTokenProvider { get; set; } + + /// Custom HTTP headers to include in all outbound requests to the provider. + [JsonPropertyName("headers")] + public IDictionary? Headers { get; set; } + + /// Maximum context window tokens for the model. + [JsonPropertyName("maxContextWindowTokens")] + public double? MaxContextWindowTokens { get; set; } + + /// Maximum output tokens for the model. + [JsonPropertyName("maxOutputTokens")] + public double? MaxOutputTokens { get; set; } + + /// Maximum prompt/input tokens for the model. + [JsonPropertyName("maxPromptTokens")] + public double? MaxPromptTokens { get; set; } + + /// Overrides for model capabilities when they cannot be inferred from modelId. + [JsonPropertyName("modelCapabilities")] + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } + + /// Well-known model ID used for capability lookup. When set, agent behavior config and token limits are inferred from this model. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } + + /// The product serving the model, reported in telemetry as `model_provider`. Set it when `type` alone cannot identify the product, such as Ollama or LM Studio behind an OpenAI-compatible endpoint. Only affects telemetry. + [JsonPropertyName("modelProvider")] + public ProviderConfigModelProvider? ModelProvider { get; set; } + + /// Provider name used for model and telemetry attribution. + [JsonPropertyName("providerName")] + public string? ProviderName { get; set; } + + /// Provider transport. Defaults to "http". + [JsonPropertyName("transport")] + public ProviderConfigTransport? Transport { get; set; } + + /// Provider type. Defaults to "openai" for generic OpenAI-compatible APIs. + [JsonPropertyName("type")] + public ProviderConfigType? Type { get; set; } + + /// Wire API format (openai/azure only). Defaults to "completions". + [JsonPropertyName("wireApi")] + public ProviderConfigWireApi? WireApi { get; set; } + + /// The model identifier sent to the provider API for inference (the "wire" model), as opposed to modelId which is the well-known base. + [JsonPropertyName("wireModel")] + public string? WireModel { get; set; } +} + +/// +/// Command-scoped GitHub credential injection for the shell commands an agent runs. +/// +/// Each channel is opt-in and independent, and injection is scoped to the individual command +/// spawn: the credential is resolved from the session's *current* authentication at every spawn +/// and reaches only spawns whose script actually invokes `git` or `gh`. Because nothing is +/// retained between spawns, replacing the session credential (`session.gitHubAuth.setCredentials`) +/// changes what the next spawned command presents — which seeding a credential into the runtime +/// process's own environment cannot do, since a child's environment is fixed at `exec`. +/// +/// The credential is matched to the host it authenticates to, so a github.com credential is never +/// presented to a GitHub Enterprise host and vice versa. Where a channel cannot express that +/// boundary it injects nothing rather than crossing it -- see `gh` below. +/// +/// This is independent of `sandboxConfig`: it is a decision about which identity the agent +/// presents, not about what the agent may touch, and it works on every platform whether or not +/// an OS sandboxing backend is available. `sandboxConfig.auth` remains the sandbox-scoped +/// spelling and is additive with this one. +/// +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ShellCredentials +{ + /// + /// Whether to authenticate the agent's `gh` commands as the session's GitHub credential, by + /// exporting `GH_TOKEN` to a spawn that runs `gh`. Any inherited `gh` credential is removed from + /// spawns that do not, so the credential stays command-scoped. + /// + /// Applies to a github.com credential only. `gh` picks its credential variable from the host a + /// command targets rather than the one the credential belongs to, and the command can choose that + /// target, so `GH_ENTERPRISE_TOKEN` would offer a single-tenant enterprise credential to every + /// other enterprise host. A session whose credential is enterprise-scoped therefore runs `gh` + /// unauthenticated; its `git` commands are unaffected, because `http.<host>.extraheader` is scoped + /// to one host by construction. Default: false (opt-in). + /// + [JsonPropertyName("gh")] + public bool? Gh { get; set; } + + /// + /// Whether to authenticate the agent's `git` commands as the session's GitHub credential, by + /// injecting an `http.<host>.extraheader` (plus `insteadOf` rewrites so SSH-spelled remotes for + /// that host use the authenticated HTTPS transport). Applied only to a spawn that runs a + /// remote-contacting `git` subcommand. Default: false (opt-in). + /// + [JsonPropertyName("git")] + public bool? Git { get; set; } +} + +/// A host-provided script sourced before each built-in shell command when its shell target matches the active shell. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ShellInitScript +{ + /// Path to the script to source. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Built-in shell that may source this script. + [JsonPropertyName("shell")] + public ShellInitScriptShell Shell { get; set; } +} + +/// Per-session settings for built-in shell tools. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ShellOptions +{ + /// Command-scoped GitHub credential injection for shell commands. + [JsonPropertyName("credentials")] + public ShellCredentials? Credentials { get; set; } + + /// Controls automatic non-interactive profile loading where supported. Explicit initScripts are unaffected. + [JsonPropertyName("initProfile")] + public ShellInitProfile? InitProfile { get; set; } + + /// + /// Ordered host-provided script paths sourced before each built-in shell command when the + /// entry's shell target matches the active shell. Use these for rc files, environment setup scripts, + /// or other custom scripts. A script that returns a nonzero status is reported, and later scripts + /// and the user command continue while the shell remains running. Because scripts are sourced into + /// the command shell, `exit`, `exec`, failures under `set -e`, or other shell-terminating behavior + /// can prevent continuation. Script standard output is preserved; Bash script stderr is discarded, + /// PowerShell exception messages are replaced, and runtime-generated failure notices omit + /// configured script paths. When sandboxing is enabled, each script must already be readable under + /// the active sandbox filesystem policy. Pass an empty array to clear the list. + /// + [JsonPropertyName("initScripts")] + public IList? InitScripts { get; set; } + + /// + /// Flags passed to the active built-in shell process on startup, replacing its default flags. + /// When omitted, the built-in Bash shell uses `--norc --noprofile`, + /// and the built-in PowerShell shell uses `-NoProfile -NoLogo`. + /// + [JsonPropertyName("processFlags")] + public IList? ProcessFlags { get; set; } +} + +/// Patch of mutable session options to apply to the running session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionUpdateOptionsParams +{ + /// Additional content-exclusion policies to merge into the session's policy set. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("additionalContentExclusionPolicies")] + public IList? AdditionalContentExclusionPolicies { get; set; } + + /// Runtime context discriminator (e.g., `cli`, `actions`). + [JsonPropertyName("agentContext")] + public string? AgentContext { get; set; } + + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } + + /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. + [JsonPropertyName("allowAllMcpServerInstructions")] + public bool? AllowAllMcpServerInstructions { get; set; } + + /// Whether to disable the `ask_user` tool (encourages autonomous behavior). + [JsonPropertyName("askUserDisabled")] + public bool? AskUserDisabled { get; set; } + + /// Allowlist of tool names available to this session. + [JsonPropertyName("availableTools")] + public IList? AvailableTools { get; set; } + + /// Options scoped to the built-in CAPI (Copilot API) provider. + [JsonPropertyName("capi")] + public CapiSessionOptions? Capi { get; set; } + + /// Identifier of the client driving the session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Whether to include the `Co-authored-by` trailer in commit messages. + [JsonPropertyName("coauthorEnabled")] + public bool? CoauthorEnabled { get; set; } + + /// Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. + [JsonPropertyName("contextTier")] + public OptionsUpdateContextTier? ContextTier { get; set; } + + /// Whether to allow auto-mode continuation across turns. + [JsonPropertyName("continueOnAutoMode")] + public bool? ContinueOnAutoMode { get; set; } + + /// Override URL for the Copilot API endpoint. + [JsonPropertyName("copilotUrl")] + public string? CopilotUrl { get; set; } + + /// Whether to default custom agents to local-only execution. + [JsonPropertyName("customAgentsLocalOnly")] + public bool? CustomAgentsLocalOnly { get; set; } + + /// Instruction source IDs to exclude from the system prompt. + [JsonPropertyName("disabledInstructionSources")] + public IList? DisabledInstructionSources { get; set; } + + /// Skill IDs that should be excluded from this session. + [JsonPropertyName("disabledSkills")] + public IList? DisabledSkills { get; set; } + + /// Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. + [JsonPropertyName("enableFileHooks")] + public bool? EnableFileHooks { get; set; } + + /// Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). + [JsonPropertyName("enableHostGitOperations")] + public bool? EnableHostGitOperations { get; set; } + + /// Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions`. + [JsonPropertyName("enableOnDemandInstructionDiscovery")] + public bool? EnableOnDemandInstructionDiscovery { get; set; } + + /// Whether to surface reasoning-summary events from the model. + [JsonPropertyName("enableReasoningSummaries")] + public bool? EnableReasoningSummaries { get; set; } + + /// Whether shell-script safety heuristics are enabled. + [JsonPropertyName("enableScriptSafety")] + public bool? EnableScriptSafety { get; set; } + + /// Whether to enable cross-session store writes and reads. + [JsonPropertyName("enableSessionStore")] + public bool? EnableSessionStore { get; set; } + + /// Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. + [JsonPropertyName("enableSkills")] + public bool? EnableSkills { get; set; } + + /// Whether to stream model responses. + [JsonPropertyName("enableStreaming")] + public bool? EnableStreaming { get; set; } + + /// How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). + [JsonPropertyName("envValueMode")] + public OptionsUpdateEnvValueMode? EnvValueMode { get; set; } + + /// Override directory for the session-events log. When unset, the runtime's default events log directory is used. + [JsonPropertyName("eventsLogDirectory")] + public string? EventsLogDirectory { get; set; } + + /// Whether subagent callback events should be forwarded into the session event log sink. + [JsonPropertyName("eventsLogIncludesSubagents")] + public bool? EventsLogIncludesSubagents { get; set; } + + /// Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. + [JsonPropertyName("excludedBuiltinAgents")] + public IList? ExcludedBuiltinAgents { get; set; } + + /// Denylist of tool names for this session. + [JsonPropertyName("excludedTools")] + public IList? ExcludedTools { get; set; } + + /// Map of feature-flag IDs to their boolean enabled state. + [JsonPropertyName("featureFlags")] + public IDictionary? FeatureFlags { get; set; } + + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("hookDirectories")] + public IList? HookDirectories { get; set; } + + /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. + [JsonPropertyName("ignoredSkillsLocations")] + public IList? IgnoredSkillsLocations { get; set; } + + /// Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. Set to null to remove the allowlist restriction. + [JsonPropertyName("includedBuiltinAgents")] + public IList? IncludedBuiltinAgents { get; set; } + + /// Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. + [JsonPropertyName("includedBuiltinSkills")] + public IList? IncludedBuiltinSkills { get; set; } + + /// Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. + [JsonPropertyName("installedPlugins")] + public IList? InstalledPlugins { get; set; } + + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } + + /// Stable integration identifier used for analytics and rate-limit attribution. + [JsonPropertyName("integrationId")] + public string? IntegrationId { get; set; } + + /// Whether experimental capabilities are enabled. + [JsonPropertyName("isExperimentalMode")] + public bool? IsExperimentalMode { get; set; } + + /// Whether interactive shell sessions are logged. + [JsonPropertyName("logInteractiveShells")] + public bool? LogInteractiveShells { get; set; } + + /// Identifier sent to LSP-style integrations. + [JsonPropertyName("lspClientName")] + public string? LspClientName { get; set; } + + /// Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). + [JsonPropertyName("manageScheduleEnabled")] + public bool? ManageScheduleEnabled { get; set; } + + /// Maximum decoded byte size of a single model-facing binary tool result (e.g. an image) persisted inline in session events and re-presented to the model on later turns / resume. Larger results are persisted as a metadata-only marker and shown to the model as a short text note. Defaults to 10 MB. + [JsonPropertyName("maxInlineBinaryBytes")] + public long? MaxInlineBinaryBytes { get; set; } + + /// The model ID to use for assistant turns. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Per-property model capability overrides for the selected model. + [JsonPropertyName("modelCapabilitiesOverrides")] + public ModelCapabilitiesOverride? ModelCapabilitiesOverrides { get; set; } + + /// Organization-level custom instructions to inject into the system prompt. + [JsonPropertyName("organizationCustomInstructions")] + public string? OrganizationCustomInstructions { get; set; } + + /// Custom model-provider configuration (BYOK). + [JsonPropertyName("provider")] + public ProviderConfig? Provider { get; set; } + + /// Reasoning effort for the selected model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } + + /// Reasoning summary mode for supported model clients. + [JsonPropertyName("reasoningSummary")] + public OptionsUpdateReasoningSummary? ReasoningSummary { get; set; } + + /// Whether the session is running in an interactive UI. + [JsonPropertyName("runningInInteractiveMode")] + public bool? RunningInInteractiveMode { get; set; } + + /// Resolved sandbox configuration. + [JsonPropertyName("sandboxConfig")] + public SandboxConfig? SandboxConfig { get; set; } + + /// Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("sandboxConfigSource")] + public SandboxConfigSource? SandboxConfigSource { get; set; } + + /// Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. + [JsonPropertyName("sessionCapabilities")] + public IList? SessionCapabilities { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Optional session limits. Pass null to clear the session limits. + [JsonPropertyName("sessionLimits")] + public SessionLimitsConfig? SessionLimits { get; set; } + + /// Per-session settings for built-in shell tools. + [JsonPropertyName("shell")] + public ShellOptions? Shell { get; set; } + + /// Use shell.initProfile instead. Shell init profile (`None` or `NonInteractive`). + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("shellInitProfile")] + public string? ShellInitProfile { get; set; } + + /// PowerShell process flags applied to built-in and user-requested shell commands. + [JsonPropertyName("shellProcessFlags")] + public IList? ShellProcessFlags { get; set; } + + /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("skillDirectories")] + public IList? SkillDirectories { get; set; } + + /// Whether to skip loading custom instruction sources. + [JsonPropertyName("skipCustomInstructions")] + public bool? SkipCustomInstructions { get; set; } + + /// Whether to skip embedding retrieval pipeline initialization and execution. + [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; } + + /// Optional path for trajectory output. + [JsonPropertyName("trajectoryFile")] + public string? TrajectoryFile { get; set; } + + /// Output verbosity level for supported models. + [JsonPropertyName("verbosity")] + public Verbosity? Verbosity { get; set; } + + /// Absolute working-directory path for shell tools. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} + +/// Parameters for (re)loading the merged LSP configuration set. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class LspInitializeRequest +{ + /// Force re-initialization even when LSP configs were already loaded for the working directory. + [JsonPropertyName("force")] + public bool? Force { get; set; } + + /// Git root used as the boundary when traversing for project-level LSP configs (supports monorepos). + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Working directory used to load project-level LSP configs. Defaults to the session working directory when omitted. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} + +/// Discovered extension metadata, including source-qualified ID, name, discovery source, status, and optional process ID. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class Extension +{ + /// Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper', 'plugin:my-plugin:my-ext'). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Extension name (directory name). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Process ID if the extension is running. + [JsonPropertyName("pid")] + public long? Pid { get; set; } + + /// Discovery source: project (.github/extensions/), user (~/.copilot/extensions/), plugin (installed plugin), or session (session-state/<id>/extensions/). + [JsonPropertyName("source")] + public ExtensionSource Source { get; set; } + + /// Current status: running, disabled, failed, or starting. + [JsonPropertyName("status")] + public ExtensionStatus Status { get; set; } +} + +/// Extensions discovered for the session, with their current status. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ExtensionList +{ + /// Discovered extensions and their current status. + [JsonPropertyName("extensions")] + public IList Extensions { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionExtensionsListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Source-qualified extension identifier to enable for the session. +[Experimental(global::GitHub.Copilot.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(global::GitHub.Copilot.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(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionExtensionsReloadRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionExtensionsReconcileRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Attachment union accepted by push input, covering files, directories, GitHub objects, blobs, snippets, and extension context. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.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(PushAttachmentGitHubCommit), "github_commit")] +[JsonDerivedType(typeof(PushAttachmentGitHubRelease), "github_release")] +[JsonDerivedType(typeof(PushAttachmentGitHubActionsJob), "github_actions_job")] +[JsonDerivedType(typeof(PushAttachmentGitHubRepository), "github_repository")] +[JsonDerivedType(typeof(PushAttachmentGitHubFileDiff), "github_file_diff")] +[JsonDerivedType(typeof(PushAttachmentGitHubTreeComparison), "github_tree_comparison")] +[JsonDerivedType(typeof(PushAttachmentGitHubUrl), "github_url")] +[JsonDerivedType(typeof(PushAttachmentGitHubFile), "github_file")] +[JsonDerivedType(typeof(PushAttachmentGitHubSnippet), "github_snippet")] +[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(global::GitHub.Copilot.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(global::GitHub.Copilot.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(global::GitHub.Copilot.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(global::GitHub.Copilot.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(global::GitHub.Copilot.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(global::GitHub.Copilot.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(global::GitHub.Copilot.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(global::GitHub.Copilot.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; } +} + +/// Pointer to a GitHub repository. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PushGitHubRepoRef +{ + /// Numeric GitHub repository id. + [JsonPropertyName("id")] + public long? Id { get; set; } + + /// Repository name (without owner). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Repository owner login (user or organization). + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; +} + +/// Pointer to a GitHub commit. +/// The github_commit variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubCommit : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_commit"; + + /// First line of the commit message. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Full commit SHA. + [JsonPropertyName("oid")] + public required string Oid { get; set; } + + /// Repository the commit belongs to. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// URL to the commit on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Pointer to a GitHub release. +/// The github_release variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubRelease : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_release"; + + /// Human-readable release name. + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// Repository the release belongs to. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// Git tag the release is anchored to. + [JsonPropertyName("tagName")] + public required string TagName { get; set; } + + /// URL to the release on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Pointer to a GitHub Actions job. +/// The github_actions_job variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubActionsJob : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_actions_job"; + + /// Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("conclusion")] + public string? Conclusion { get; set; } + + /// Job id within the workflow run. + [JsonPropertyName("jobId")] + public required long JobId { get; set; } + + /// Display name of the job. + [JsonPropertyName("jobName")] + public required string JobName { get; set; } + + /// Repository the workflow run belongs to. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// URL to the job on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } + + /// Display name of the workflow the job ran in. + [JsonPropertyName("workflowName")] + public required string WorkflowName { get; set; } +} + +/// Pointer to a GitHub repository. +/// The github_repository variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubRepository : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_repository"; + + /// Short description of the repository. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ref")] + public string? Ref { get; set; } + + /// Repository pointer. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// URL to the repository on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// One side of a file diff (head or base). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PushAttachmentGitHubFileDiffSide +{ + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Git ref (branch, tag, or commit SHA) the file is read at. + [JsonPropertyName("ref")] + public string Ref { get; set; } = string.Empty; + + /// Repository the file lives in. + [JsonPropertyName("repo")] + public PushGitHubRepoRef Repo { get => field ??= new(); set; } +} + +/// Pointer to a single-file diff. At least one of `head` and `base` must be present. +/// The github_file_diff variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubFileDiff : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_file_diff"; + + /// File location on the base side of the diff. Absent for additions. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("base")] + public PushAttachmentGitHubFileDiffSide? Base { get; set; } + + /// File location on the head side of the diff. Absent for deletions. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("head")] + public PushAttachmentGitHubFileDiffSide? Head { get; set; } + + /// URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL). + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// One side of a tree comparison (head or base). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PushAttachmentGitHubTreeComparisonSide +{ + /// Repository the revision belongs to. + [JsonPropertyName("repo")] + public PushGitHubRepoRef Repo { get => field ??= new(); set; } + + /// Git revision (branch, tag, or commit SHA). + [JsonPropertyName("revision")] + public string Revision { get; set; } = string.Empty; +} + +/// Pointer to a comparison between two git revisions. +/// The github_tree_comparison variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubTreeComparison : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_tree_comparison"; + + /// Base side of the comparison. + [JsonPropertyName("base")] + public required PushAttachmentGitHubTreeComparisonSide Base { get; set; } + + /// Head side of the comparison. + [JsonPropertyName("head")] + public required PushAttachmentGitHubTreeComparisonSide Head { get; set; } + + /// URL to the comparison on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Generic GitHub URL reference. +/// The github_url variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubUrl : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_url"; + + /// URL to the GitHub resource. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Pointer to a file in a GitHub repository at a specific ref. +/// The github_file variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubFile : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_file"; + + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public required string Path { get; set; } + + /// Git ref the file is read at (branch, tag, or commit SHA). + [JsonPropertyName("ref")] + public required string Ref { get; set; } + + /// Repository the file lives in. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// URL to the file on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Pointer to a line range inside a file in a GitHub repository. +/// The github_snippet variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubSnippet : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_snippet"; + + /// Line range the snippet covers. + [JsonPropertyName("lineRange")] + public required PushAttachmentFileLineRange LineRange { get; set; } + + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public required string Path { get; set; } + + /// Git ref the file is read at (branch, tag, or commit SHA). + [JsonPropertyName("ref")] + public required string Ref { get; set; } + + /// Repository the file lives in. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// URL to the snippet on GitHub (with line anchor). + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Blob attachment with inline base64-encoded data. +/// The blob variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentBlob : PushAttachment +{ + /// + [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; } +} + +/// Slim input shape for extension_context attachments; identity fields are runtime-derived. +/// The extension_context variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentExtensionContext : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "extension_context"; + + /// 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; } +} + +/// Parameters for session.extensions.sendAttachmentsToMessage. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +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; +} + +/// A tool name and arguments to execute through the session's native invocation pipeline. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ToolsExecuteRequest +{ + /// Arguments supplied to the tool. + [JsonPropertyName("arguments")] + public JsonElement Arguments { get; set; } + + /// Name of the currently offered tool to execute. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Optional identifier used to correlate this invocation with its tool call. + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } +} + +/// Custom grammar input format accepted by a built-in tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class BuiltinToolFormat +{ + /// Grammar definition accepted by the tool. + [JsonPropertyName("definition")] + public string Definition { get; set; } = string.Empty; + + /// Grammar syntax used by the format definition. + [JsonPropertyName("syntax")] + public string Syntax { get; set; } = string.Empty; + + /// Custom input-format discriminator. + [JsonPropertyName("type")] + public BuiltinToolFormatType Type { get; set; } +} + +/// JSON Schema object accepted by a built-in tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class BuiltinToolInputSchema +{ + /// Root type of the tool input schema. + [JsonPropertyName("type")] + public BuiltinToolInputSchemaType Type { get; set; } +} + +/// Rust-owned metadata and input schema for a built-in tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class BuiltinToolDescriptor +{ + /// Model-facing description of the tool's behavior. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Optional custom input format used instead of a JSON Schema. + [JsonPropertyName("format")] + public BuiltinToolFormat? Format { get; set; } + + /// Whether the tool provides a specialized intention summary. + [JsonPropertyName("hasSummariseIntention")] + public bool HasSummariseIntention { get; set; } + + /// JSON Schema for the tool input, or null when the tool uses a custom format. + [JsonPropertyName("inputSchema")] + public BuiltinToolInputSchema? InputSchema { get; set; } + + /// Optional supplemental usage instructions for the tool. + [JsonPropertyName("instructions")] + public string? Instructions { get; set; } + + /// Whether the tool executes commands in a terminal. + [JsonPropertyName("isTerminal")] + public bool IsTerminal { get; set; } + + /// Stable name used to invoke the built-in tool. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Policy describing which tool metadata may be recorded without obfuscation. + [JsonPropertyName("safeForTelemetry")] + public JsonElement SafeForTelemetry { get; set; } + + /// Optional human-readable title for the tool. + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// Optional tool category discriminator. + [JsonPropertyName("type")] + public string? Type { get; set; } +} + +/// Rust-owned built-in tool descriptors for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolsGetBuiltinDescriptorsResult +{ + /// Built-in tool descriptors materialized for the session. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } +} + +/// Shell-specific names and description lines used to materialize built-in shell tool descriptors. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolsShellDescriptorConfig +{ + /// Additional model-facing shell description lines. + [JsonPropertyName("descriptionLines")] + public IList DescriptionLines { get => field ??= []; set; } + + /// Human-readable shell name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + /// Tool name used to list active shells. + [JsonPropertyName("listShellsToolName")] + public string ListShellsToolName { get; set; } = string.Empty; + + /// Tool name used to read shell output. + [JsonPropertyName("readShellToolName")] + public string ReadShellToolName { get; set; } = string.Empty; + + /// Tool name used to start shell commands. + [JsonPropertyName("shellToolName")] + public string ShellToolName { get; set; } = string.Empty; + + /// Stable shell type identifier. + [JsonPropertyName("shellType")] + public string ShellType { get; set; } = string.Empty; + + /// Tool name used to stop shell commands. + [JsonPropertyName("stopShellToolName")] + public string StopShellToolName { get; set; } = string.Empty; +} + +/// Options controlling how Rust-owned built-in tool descriptors are materialized. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ToolsGetBuiltinDescriptorsRequest +{ + /// Whether background task completion notifications are enabled. + [JsonPropertyName("backgroundTaskNotificationsEnabled")] + public bool? BackgroundTaskNotificationsEnabled { get; set; } + + /// Whether tool descriptors should include authoring metadata. + [JsonPropertyName("includeAuthor")] + public bool? IncludeAuthor { get; set; } + + /// Whether descriptors should favor fewer user-intervention prompts. + [JsonPropertyName("reduceUserIntervention")] + public bool? ReduceUserIntervention { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Shell-specific names and description lines for shell tools. + [JsonPropertyName("shellConfig")] + public ToolsShellDescriptorConfig? ShellConfig { get; set; } + + /// Whether the configured shell supports PowerShell 7 syntax. + [JsonPropertyName("shellSupportsPowerShell7Syntax")] + public bool? ShellSupportsPowerShell7Syntax { get; set; } + + /// Default shell timeout in milliseconds. + [JsonPropertyName("shellTimeoutMs")] + public double? ShellTimeoutMs { get; set; } + + /// Whether semantic skill lookup is available. + [JsonPropertyName("skillEmbeddingEnabled")] + public bool? SkillEmbeddingEnabled { get; set; } +} + +/// Task completion notification with summary from the agent. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TaskCompleteData +{ + /// Structured blocker details when outcome is blocked. + [JsonPropertyName("blocker")] + public TaskBlocker? Blocker { get; set; } + + /// Active autopilot objective ID evaluated by the completion reviewer. + [JsonPropertyName("objectiveId")] + public long? ObjectiveId { get; set; } + + /// Semantic completion decision. Absent on legacy events and invalid tool calls. + [JsonPropertyName("outcome")] + public TaskCompletionOutcome? Outcome { get; set; } + + /// Label-safe runtime rationale for the completion decision (e.g. a cancellation or pause/resume downgrade), when one applies. Reviewer-authored rationale is intentionally omitted here because this event has no IFC label channel; the reviewer's findings remain available through its own labeled sub-agent events. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether the task was accepted as complete. False when validation failed or completion was rejected or blocked by the reviewer. + [JsonPropertyName("success")] + public bool? Success { get; set; } + + /// Summary of the completed task, provided by the agent. + [JsonPropertyName("summary")] + public string? Summary { get; set; } +} + +/// Binary result returned by a tool for the model. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ExternalToolTextResultForLlmBinaryResultsForLlm +{ + /// Base64-encoded binary data. + [Base64String] + [JsonPropertyName("data")] + public string Data { get; set; } = string.Empty; + + /// Human-readable description of the binary data. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Optional metadata from the producing tool. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } + + /// MIME type of the binary data. + [JsonPropertyName("mimeType")] + public string MimeType { get; set; } = string.Empty; + + /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. + [JsonPropertyName("type")] + public ExternalToolTextResultForLlmBinaryResultsForLlmType Type { get; set; } +} + +/// A content block within a tool result, which may be text, terminal output, image, audio, or a resource. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentText), "text")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentTerminal), "terminal")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentShellExit), "shell_exit")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentImage), "image")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentAudio), "audio")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResourceLink), "resource_link")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResource), "resource")] +public partial class ExternalToolTextResultForLlmContent +{ + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; +} + + +/// Plain text content block. +/// The text variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ExternalToolTextResultForLlmContentText : ExternalToolTextResultForLlmContent +{ + /// + [JsonIgnore] + public override string Type => "text"; + + /// The text content. + [JsonPropertyName("text")] + public required string Text { get; set; } +} + +/// Terminal/shell output content block with optional exit code and working directory. +/// The terminal variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ExternalToolTextResultForLlmContentTerminal : ExternalToolTextResultForLlmContent +{ + /// + [JsonIgnore] + public override string Type => "terminal"; + + /// Working directory where the command was executed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } + + /// Process exit code, if the command has completed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } + + /// Terminal/shell output text. + [JsonPropertyName("text")] + public required string Text { get; set; } +} + +/// Shell command exit metadata with optional output preview. +/// The shell_exit variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ExternalToolTextResultForLlmContentShellExit : ExternalToolTextResultForLlmContent +{ + /// + [JsonIgnore] + public override string Type => "shell_exit"; + + /// Working directory where the shell command was executed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } + + /// Exit code from the completed shell command. + [JsonPropertyName("exitCode")] + public required long ExitCode { get; set; } + + /// Path reported in the shell session's filesystem namespace when shell output exceeded the configured large-output threshold. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("outputFilePath")] + public string? OutputFilePath { get; set; } + + /// Output associated with this shell command, if available. May be partial, truncated, or a preview; not guaranteed to be full output. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("outputPreview")] + public string? OutputPreview { get; set; } + + /// Whether outputPreview is known to be incomplete or truncated. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("outputTruncated")] + public bool? OutputTruncated { get; set; } + + /// Shell id, as assigned by Copilot runtime. + [JsonPropertyName("shellId")] + public required string ShellId { get; set; } +} + +/// Image content block with base64-encoded data. +/// The image variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ExternalToolTextResultForLlmContentImage : ExternalToolTextResultForLlmContent +{ + /// + [JsonIgnore] + public override string Type => "image"; + + /// Base64-encoded image data. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// MIME type of the image (e.g., image/png, image/jpeg). + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } +} + +/// Audio content block with base64-encoded data. +/// The audio variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ExternalToolTextResultForLlmContentAudio : ExternalToolTextResultForLlmContent +{ + /// + [JsonIgnore] + public override string Type => "audio"; + + /// Base64-encoded audio data. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// MIME type of the audio (e.g., audio/wav, audio/mpeg). + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } +} + +/// Icon image for a resource. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ExternalToolTextResultForLlmContentResourceLinkIcon +{ + /// MIME type of the icon image. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Available icon sizes (e.g., ['16x16', '32x32']). + [JsonPropertyName("sizes")] + public IList? Sizes { get; set; } + + /// URL or path to the icon image. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; + + /// Theme variant this icon is intended for. + [JsonPropertyName("theme")] + public ExternalToolTextResultForLlmContentResourceLinkIconTheme? Theme { get; set; } +} + +/// Resource link content block referencing an external resource. +/// The resource_link variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ExternalToolTextResultForLlmContentResourceLink : ExternalToolTextResultForLlmContent +{ + /// + [JsonIgnore] + public override string Type => "resource_link"; + + /// Human-readable description of the resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Icons associated with this resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("icons")] + public IList? Icons { get; set; } + + /// MIME type of the resource content. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Resource name identifier. + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// Size of the resource in bytes. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("size")] + public long? Size { get; set; } + + /// Human-readable display title for the resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// URI identifying the resource. + [JsonPropertyName("uri")] + public required string Uri { get; set; } +} + +/// Embedded resource content block with inline text or binary data. +/// The resource variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ExternalToolTextResultForLlmContentResource : ExternalToolTextResultForLlmContent +{ + /// + [JsonIgnore] + public override string Type => "resource"; + + /// The embedded resource contents, either text or base64-encoded binary. + [JsonPropertyName("resource")] + public required JsonElement Resource { get; set; } +} + +/// A message injected by a tool result. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolResultNewMessage +{ + /// Message content to inject after the tool result. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Source attributed to the injected message. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; +} + +/// RPC data type for TaskCompletionDecision operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TaskCompletionDecision +{ + /// Objective eligibility token captured when the decision was evaluated. + [JsonPropertyName("completionEligibilityToken")] + public long? CompletionEligibilityToken { get; set; } + + /// Whether completion was accepted after the reviewer-rejection budget was exhausted. + [JsonPropertyName("completionRejectionBudgetExhausted")] + public bool? CompletionRejectionBudgetExhausted { get; set; } + + /// Active autopilot objective evaluated by the completion reviewer. + [JsonPropertyName("objectiveId")] + public long? ObjectiveId { get; set; } + + /// Semantic result of evaluating the task completion request. + [JsonPropertyName("outcome")] + public TaskCompletionOutcome Outcome { get; set; } + + /// Rationale for the completion decision, when one is available. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether the rationale was derived from completion-reviewer output. + [JsonPropertyName("reviewerDerived")] + public bool? ReviewerDerived { get; set; } + + /// Information-flow metadata captured from the completion reviewer. + [JsonPropertyName("reviewerResultMeta")] + public JsonElement? ReviewerResultMeta { get; set; } +} + +/// Expanded canonical result returned by a session tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolResultExpanded +{ + /// Base64-encoded binary results returned to the model. + [JsonPropertyName("binaryResultsForLlm")] + public IList? BinaryResultsForLlm { get; set; } + + /// Sources returned by the tool that the model may cite. + [JsonPropertyName("citableSources")] + public IList? CitableSources { get; set; } + + /// Structured content blocks returned to the model. + [JsonPropertyName("contents")] + public IList? Contents { get; set; } + + /// Error message for an unsuccessful execution. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Metadata propagated with the tool result, including information-flow labels. + [JsonPropertyName("mcpMeta")] + public IDictionary? McpMeta { get; set; } + + /// Messages to inject after the tool result. + [JsonPropertyName("newMessages")] + public IList? NewMessages { get; set; } - /// PowerShell process flags applied to built-in and user-requested shell commands. - [JsonPropertyName("shellProcessFlags")] - public IList? ShellProcessFlags { get; set; } + /// Whether post-tool-use failure hooks have already processed this result. + [JsonPropertyName("postToolUseFailureHooksProcessed")] + public bool? PostToolUseFailureHooksProcessed { get; set; } - /// Additional directories to search for skills. - [JsonPropertyName("skillDirectories")] - public IList? SkillDirectories { get; set; } + /// Execution outcome classification. + [JsonPropertyName("resultType")] + public ToolResultType ResultType { get; set; } - /// Whether to skip loading custom instruction sources. - [JsonPropertyName("skipCustomInstructions")] - public bool? SkipCustomInstructions { get; set; } + /// Detailed log content available for session display. + [JsonPropertyName("sessionLog")] + public string? SessionLog { get; set; } - /// Whether to skip embedding retrieval pipeline initialization and execution. - [JsonPropertyName("skipEmbeddingRetrieval")] - public bool? SkipEmbeddingRetrieval { get; set; } + /// Skill invocation metadata produced by the tool. + [JsonPropertyName("skillInvocation")] + public JsonElement? SkillInvocation { 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; } + /// Whether large-output post-processing should be skipped. + [JsonPropertyName("skipLargeOutputProcessing")] + public bool? SkipLargeOutputProcessing { get; set; } - /// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. - [JsonPropertyName("toolFilterPrecedence")] - public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; } + /// Structured result content in addition to the model-facing text. + [JsonPropertyName("structuredContent")] + public JsonElement? StructuredContent { get; set; } - /// Optional path for trajectory output. - [JsonPropertyName("trajectoryFile")] - public string? TrajectoryFile { get; set; } + /// Completion-review decision produced by the task-completion tool. + [JsonPropertyName("taskCompletionDecision")] + public TaskCompletionDecision? TaskCompletionDecision { get; set; } - /// Output verbosity level for supported models. - [JsonPropertyName("verbosity")] - public Verbosity? Verbosity { get; set; } + /// Text result returned to the model. + [JsonPropertyName("textResultForLlm")] + public string TextResultForLlm { get; set; } = string.Empty; - /// Absolute working-directory path for shell tools. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// Deferred tool names made available by this result. + [JsonPropertyName("toolReferences")] + public IList? ToolReferences { get; set; } + + /// Tool-specific telemetry payload. + [JsonPropertyName("toolTelemetry")] + public JsonElement? ToolTelemetry { get; set; } + + /// Optional UI resource produced by the tool. + [JsonPropertyName("uiResource")] + public JsonElement? UiResource { get; set; } } -/// Parameters for (re)loading the merged LSP configuration set. +/// Task-completion tool arguments and final result used to build a label-safe session event payload. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LspInitializeRequest +internal sealed class ToolsTaskCompleteEventDataRequest { - /// Force re-initialization even when LSP configs were already loaded for the working directory. - [JsonPropertyName("force")] - public bool? Force { get; set; } - - /// Git root used as the boundary when traversing for project-level LSP configs (supports monorepos). - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// Final expanded result returned by the task_complete tool. + [JsonPropertyName("finalResult")] + public ToolResultExpanded FinalResult { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Working directory used to load project-level LSP configs. Defaults to the session working directory when omitted. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// Arguments supplied to the completed task_complete tool call. + [JsonPropertyName("toolArgs")] + public JsonElement ToolArgs { get; set; } } -/// Discovered extension metadata, including source-qualified ID, name, discovery source, status, and optional process ID. +/// Indicates whether the external tool call result was handled successfully. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Extension +public sealed class HandlePendingToolCallResult { - /// Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper', 'plugin:my-plugin:my-ext'). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Extension name (directory name). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Process ID if the extension is running. - [JsonPropertyName("pid")] - public long? Pid { get; set; } - - /// Discovery source: project (.github/extensions/), user (~/.copilot/extensions/), plugin (installed plugin), or session (session-state/<id>/extensions/). - [JsonPropertyName("source")] - public ExtensionSource Source { get; set; } - - /// Current status: running, disabled, failed, or starting. - [JsonPropertyName("status")] - public ExtensionStatus Status { get; set; } + /// Whether the tool call result was handled successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Extensions discovered for the session, with their current status. +/// Pending external tool call request ID, with the tool result or an error describing why it failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionList +internal sealed class HandlePendingToolCallRequest { - /// Discovered extensions and their current status. - [JsonPropertyName("extensions")] - public IList Extensions { get => field ??= []; set; } -} + /// Error message if the tool call failed. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Request ID of the pending tool call. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Tool call result (string or expanded result object). + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionExtensionsListRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Source-qualified extension identifier to enable for the session. +/// External tool call of the session or one of its sub-agents that is still waiting for session.tools.handlePendingToolCall. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ExtensionsEnableRequest +public sealed class PendingExternalToolRequest { - /// Source-qualified extension ID to enable. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Sub-agent instance identifier (the envelope agentId of its events) of the agent that issued the call; absent for calls issued by the root agent. + [JsonPropertyName("agentId")] + public string? AgentId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Arguments to pass to the external tool. + [JsonPropertyName("arguments")] + public JsonElement? Arguments { get; set; } + + /// Stable identity of the provider that offered the tool, for hosts that route extension-owned tools by provider. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Request ID to pass to session.tools.handlePendingToolCall. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Tool call ID assigned to this external tool invocation. + [JsonPropertyName("toolCallId")] + public string ToolCallId { get; set; } = string.Empty; + + /// Name of the external tool to invoke. + [JsonPropertyName("toolName")] + public string ToolName { get; set; } = string.Empty; } -/// Source-qualified extension identifier to disable for the session. +/// External tool calls still waiting for a result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ExtensionsDisableRequest +public sealed class PendingExternalToolRequestList { - /// 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; + /// External tool calls of the session and its sub-agents that session.tools.handlePendingToolCall would still accept, in the order they were requested. Includes calls that were pending when the session was last suspended and resumed with pending work continued, so a host that did not observe the original external_tool.requested event can answer them. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } } -/// Identifies the target session. +/// No parameters; returns the external tool calls of the session and its sub-agents that are still waiting for a result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionExtensionsReloadRequest +internal sealed class ToolsListPendingRequestsRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Attachment union accepted by push input, covering files, directories, GitHub objects, blobs, snippets, and extension context. -/// Polymorphic base type discriminated by type. +/// Resolve, build, and validate the runtime tool list for this session. Subagent 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. [Experimental(global::GitHub.Copilot.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(PushAttachmentGitHubCommit), "github_commit")] -[JsonDerivedType(typeof(PushAttachmentGitHubRelease), "github_release")] -[JsonDerivedType(typeof(PushAttachmentGitHubActionsJob), "github_actions_job")] -[JsonDerivedType(typeof(PushAttachmentGitHubRepository), "github_repository")] -[JsonDerivedType(typeof(PushAttachmentGitHubFileDiff), "github_file_diff")] -[JsonDerivedType(typeof(PushAttachmentGitHubTreeComparison), "github_tree_comparison")] -[JsonDerivedType(typeof(PushAttachmentGitHubUrl), "github_url")] -[JsonDerivedType(typeof(PushAttachmentGitHubFile), "github_file")] -[JsonDerivedType(typeof(PushAttachmentGitHubSnippet), "github_snippet")] -[JsonDerivedType(typeof(PushAttachmentBlob), "blob")] -[JsonDerivedType(typeof(PushAttachmentExtensionContext), "extension_context")] -public partial class PushAttachment +public sealed class ToolsInitializeAndValidateResult { - /// 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. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentFileLineRange +internal sealed class SessionToolsInitializeAndValidateRequest { - /// 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; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// File attachment. -/// The file variant of . +/// Lightweight metadata for a currently initialized session tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentFile : PushAttachment +public sealed class CurrentToolMetadata { - /// - [JsonIgnore] - public override string Type => "file"; + /// Whether the tool is loaded on demand via tool search. + [JsonPropertyName("deferLoading")] + public bool? DeferLoading { get; set; } - /// User-facing display name for the attachment. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Tool description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// 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; } + /// JSON Schema for tool input. + [JsonPropertyName("input_schema")] + public IDictionary? InputSchema { get; set; } - /// Absolute file path. - [JsonPropertyName("path")] - public required string Path { get; set; } -} + /// MCP server name for MCP-backed tools. + [JsonPropertyName("mcpServerName")] + public string? McpServerName { get; set; } -/// Directory attachment. -/// The directory variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentDirectory : PushAttachment -{ - /// - [JsonIgnore] - public override string Type => "directory"; + /// Raw MCP tool name for MCP-backed tools. + [JsonPropertyName("mcpToolName")] + public string? McpToolName { get; set; } - /// User-facing display name for the attachment. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Model-facing tool name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Absolute directory path. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Optional MCP/config namespaced tool name. + [JsonPropertyName("namespacedName")] + public string? NamespacedName { get; set; } } -/// End position of the selection. +/// Current lightweight tool metadata snapshot for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentSelectionDetailsEnd +public sealed class ToolsGetCurrentMetadataResult { - /// 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; } + /// Current tool metadata, or null when tools have not been initialized yet. + [JsonPropertyName("tools")] + public IList? Tools { get; set; } } -/// Start position of the selection. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentSelectionDetailsStart +internal sealed class SessionToolsGetCurrentMetadataRequest { - /// 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; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Position range of the selection within the file. +/// Empty result after replacing the calling connection's externally implemented tools. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentSelectionDetails +public sealed class ToolsSetResult { - /// 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 . +/// Serializable definition of a caller-implemented tool whose execution is handled over the SDK connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentSelection : PushAttachment +public sealed class ProtocolExternalToolDefinition { - /// - [JsonIgnore] - public override string Type => "selection"; - - /// User-facing display name for the selection. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Tool-loading deferral policy. + [JsonPropertyName("defer")] + public ProtocolExternalToolDefer? Defer { get; set; } - /// Absolute path to the file containing the selection. - [JsonPropertyName("filePath")] - public required string FilePath { get; set; } + /// Model-visible explanation of what the tool does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Position range of the selection within the file. - [JsonPropertyName("selection")] - public required PushAttachmentSelectionDetails Selection { get; set; } + /// Whether the tool executes commands in a terminal. + [JsonPropertyName("isTerminal")] + public bool? IsTerminal { get; set; } - /// The selected text content. - [JsonPropertyName("text")] - public required string Text { get; set; } -} + /// Optional caller-defined metadata associated with the tool. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } -/// GitHub issue, pull request, or discussion reference. -/// The github_reference variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubReference : PushAttachment -{ - /// - [JsonIgnore] - public override string Type => "github_reference"; + /// Unique model-visible tool name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Issue, pull request, or discussion number. - [JsonPropertyName("number")] - public required long Number { get; set; } + /// Whether this definition replaces a built-in tool with the same name. + [JsonPropertyName("overridesBuiltInTool")] + public bool? OverridesBuiltInTool { get; set; } - /// Type of GitHub reference. - [JsonPropertyName("referenceType")] - public required PushAttachmentGitHubReferenceType ReferenceType { get; set; } + /// JSON Schema describing the tool's input arguments. + [JsonPropertyName("parameters")] + public IDictionary? Parameters { get; set; } - /// Current state of the referenced item (e.g., open, closed, merged). - [JsonPropertyName("state")] - public required string State { get; set; } + /// Whether execution bypasses the normal tool permission prompt. + [JsonPropertyName("skipPermission")] + public bool? SkipPermission { get; set; } - /// Title of the referenced item. + /// Optional human-readable display title. [JsonPropertyName("title")] - public required string Title { get; set; } - - /// URL to the referenced item on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + public string? Title { get; set; } } -/// Pointer to a GitHub repository. +/// Complete externally implemented tool list for the calling connection. An empty list removes every tool previously supplied by that connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushGitHubRepoRef +internal sealed class ToolsSetRequest { - /// Numeric GitHub repository id. - [JsonPropertyName("id")] - public long? Id { get; set; } - - /// Repository name (without owner). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Repository owner login (user or organization). - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; + /// Complete replacement list for the calling connection. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } } -/// Pointer to a GitHub commit. -/// The github_commit variant of . +/// Empty result after applying subagent settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubCommit : PushAttachment +public sealed class ToolsUpdateSubagentSettingsResult { - /// - [JsonIgnore] - public override string Type => "github_commit"; - - /// First line of the commit message. - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Full commit SHA. - [JsonPropertyName("oid")] - public required string Oid { get; set; } - - /// Repository the commit belongs to. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } - - /// URL to the commit on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } } -/// Pointer to a GitHub release. -/// The github_release variant of . +/// Subagent model, reasoning effort, context tier, and auto-invocation settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubRelease : PushAttachment +public sealed class SubagentSettingsEntry { - /// - [JsonIgnore] - public override string Type => "github_release"; + /// Whether this agent's runtime-defined proactive invocation prompting is enabled, if supported. Currently consumed by the built-in rubber-duck agent. + [JsonPropertyName("autoInvoke")] + public bool? AutoInvoke { get; set; } - /// Human-readable release name. - [JsonPropertyName("name")] - public required string Name { get; set; } + /// Context tier override for matching subagents. + [JsonPropertyName("contextTier")] + public SubagentSettingsEntryContextTier? ContextTier { get; set; } - /// Repository the release belongs to. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Reasoning effort override for matching subagents. + [JsonPropertyName("effortLevel")] + public string? EffortLevel { get; set; } - /// Git tag the release is anchored to. - [JsonPropertyName("tagName")] - public required string TagName { get; set; } + /// Model override for matching subagents. + [JsonPropertyName("model")] + public string? Model { get; set; } - /// URL to the release on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Whether the configured model strategy is preferred or required. + [JsonPropertyName("modelPolicy")] + public AgentModelPolicy? ModelPolicy { get; set; } } -/// Pointer to a GitHub Actions job. -/// The github_actions_job variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubActionsJob : PushAttachment +/// Configured per-agent subagent overrides. +public sealed class UpdateSubagentSettingsRequestSubagents { - /// - [JsonIgnore] - public override string Type => "github_actions_job"; - - /// Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("conclusion")] - public string? Conclusion { get; set; } - - /// Job id within the workflow run. - [JsonPropertyName("jobId")] - public required long JobId { get; set; } - - /// Display name of the job. - [JsonPropertyName("jobName")] - public required string JobName { get; set; } - - /// Repository the workflow run belongs to. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } - - /// URL to the job on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } - - /// Display name of the workflow the job ran in. - [JsonPropertyName("workflowName")] - public required string WorkflowName { get; set; } -} + /// Per-agent settings keyed by subagent agent_type. + [JsonPropertyName("agents")] + public IDictionary? Agents { get; set; } -/// Pointer to a GitHub repository. -/// The github_repository variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubRepository : PushAttachment -{ - /// - [JsonIgnore] - public override string Type => "github_repository"; + /// Names of subagents the user has turned off; they cannot be dispatched. + [JsonPropertyName("disabledSubagents")] + public IList? DisabledSubagents { get; set; } - /// Short description of the repository. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Maximum number of subagents that can run concurrently; applies to usage-based billing users only. + [JsonPropertyName("maxConcurrency")] + public int? MaxConcurrency { get; set; } - /// Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ref")] - public string? Ref { get; set; } + /// Maximum subagent nesting depth; applies to usage-based billing users only. + [JsonPropertyName("maxDepth")] + public int? MaxDepth { get; set; } +} - /// Repository pointer. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } +/// Subagent settings to apply to the current session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UpdateSubagentSettingsRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// URL to the repository on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Subagent settings to apply, or null to clear the live session override. + [JsonPropertyName("subagents")] + public UpdateSubagentSettingsRequestSubagents? Subagents { get; set; } } -/// One side of a file diff (head or base). +/// RPC data type for SessionCommandsList operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentGitHubFileDiffSide +public sealed class SessionCommandsListRequest { - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Include runtime built-in commands. + [JsonPropertyName("includeBuiltins")] + public bool? IncludeBuiltins { get; set; } - /// Git ref (branch, tag, or commit SHA) the file is read at. - [JsonPropertyName("ref")] - public string Ref { get; set; } = string.Empty; + /// Include commands registered by protocol clients, including SDK clients and extensions. + [JsonPropertyName("includeClientCommands")] + public bool? IncludeClientCommands { get; set; } - /// Repository the file lives in. - [JsonPropertyName("repo")] - public PushGitHubRepoRef Repo { get => field ??= new(); set; } + /// Include enabled user-invocable skills and commands. + [JsonPropertyName("includeSkills")] + public bool? IncludeSkills { get; set; } } -/// Pointer to a single-file diff. At least one of `head` and `base` must be present. -/// The github_file_diff variant of . +/// RPC data type for SessionCommandsListRequestWithSession operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubFileDiff : PushAttachment +internal sealed class SessionCommandsListRequestWithSession { - /// - [JsonIgnore] - public override string Type => "github_file_diff"; + /// Include runtime built-in commands. + [JsonPropertyName("includeBuiltins")] + public bool? IncludeBuiltins { get; set; } - /// File location on the base side of the diff. Absent for additions. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("base")] - public PushAttachmentGitHubFileDiffSide? Base { get; set; } + /// Include commands registered by protocol clients, including SDK clients and extensions. + [JsonPropertyName("includeClientCommands")] + public bool? IncludeClientCommands { get; set; } - /// File location on the head side of the diff. Absent for deletions. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("head")] - public PushAttachmentGitHubFileDiffSide? Head { get; set; } + /// Include enabled user-invocable skills and commands. + [JsonPropertyName("includeSkills")] + public bool? IncludeSkills { get; set; } - /// URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL). - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// One side of a tree comparison (head or base). +/// Result of invoking the slash command (text output, prompt to send to the agent, completion, or subcommand selection). +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentGitHubTreeComparisonSide +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SlashCommandInvocationResultText), "text")] +[JsonDerivedType(typeof(SlashCommandInvocationResultAgentPrompt), "agent-prompt")] +[JsonDerivedType(typeof(SlashCommandInvocationResultCompleted), "completed")] +[JsonDerivedType(typeof(SlashCommandInvocationResultSelectSubcommand), "select-subcommand")] +[JsonDerivedType(typeof(SlashCommandInvocationResultAddTimelineEntry), "add-timeline-entry")] +[JsonDerivedType(typeof(SlashCommandInvocationResultShowDialog), "show-dialog")] +[JsonDerivedType(typeof(SlashCommandInvocationResultSetModel), "set-model")] +[JsonDerivedType(typeof(SlashCommandInvocationResultSetPlanModel), "set-plan-model")] +public partial class SlashCommandInvocationResult { - /// Repository the revision belongs to. - [JsonPropertyName("repo")] - public PushGitHubRepoRef Repo { get => field ??= new(); set; } - - /// Git revision (branch, tag, or commit SHA). - [JsonPropertyName("revision")] - public string Revision { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Pointer to a comparison between two git revisions. -/// The github_tree_comparison variant of . + +/// Slash-command invocation result containing text output plus Markdown/ANSI rendering flags. +/// The text variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubTreeComparison : PushAttachment +public partial class SlashCommandInvocationResultText : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "github_tree_comparison"; + public override string Kind => "text"; - /// Base side of the comparison. - [JsonPropertyName("base")] - public required PushAttachmentGitHubTreeComparisonSide Base { get; set; } + /// Whether text contains Markdown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("markdown")] + public bool? Markdown { get; set; } - /// Head side of the comparison. - [JsonPropertyName("head")] - public required PushAttachmentGitHubTreeComparisonSide Head { get; set; } + /// Whether ANSI sequences should be preserved. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("preserveAnsi")] + public bool? PreserveAnsi { get; set; } - /// URL to the comparison on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } -} + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } -/// Generic GitHub URL reference. -/// The github_url variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubUrl : PushAttachment -{ - /// - [JsonIgnore] - public override string Type => "github_url"; + /// Present when the invocation changed the sandbox for this session only. Nothing was persisted, so consumers must mirror the change onto the live session rather than reloading settings, and must not treat it as a settings change. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("sandboxSessionChange")] + public SandboxSessionChange? SandboxSessionChange { get; set; } - /// URL to the GitHub resource. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Text output for the client to render. + [JsonPropertyName("text")] + public required string Text { get; set; } } -/// Pointer to a file in a GitHub repository at a specific ref. -/// The github_file variant of . +/// Slash-command invocation result that submits an agent prompt, with display prompt, optional mode, optional user-facing notice, and settings-change flag. +/// The agent-prompt variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubFile : PushAttachment +public partial class SlashCommandInvocationResultAgentPrompt : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "github_file"; + public override string Kind => "agent-prompt"; - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Prompt text to display to the user. + [JsonPropertyName("displayPrompt")] + public required string DisplayPrompt { get; set; } - /// Git ref the file is read at (branch, tag, or commit SHA). - [JsonPropertyName("ref")] - public required string Ref { get; set; } + /// Optional target session mode for the agent prompt. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mode")] + public SessionMode? Mode { get; set; } - /// Repository the file lives in. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Optional user-facing notice to show before the prompt is submitted. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("notice")] + public string? Notice { get; set; } - /// URL to the file on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Prompt to submit to the agent. + [JsonPropertyName("prompt")] + public required string Prompt { get; set; } + + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Pointer to a line range inside a file in a GitHub repository. -/// The github_snippet variant of . +/// Slash-command invocation result indicating completion, with optional message and settings-change flag. +/// The completed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubSnippet : PushAttachment +public partial class SlashCommandInvocationResultCompleted : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "github_snippet"; - - /// Line range the snippet covers. - [JsonPropertyName("lineRange")] - public required PushAttachmentFileLineRange LineRange { get; set; } - - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public required string Path { get; set; } + public override string Kind => "completed"; - /// Git ref the file is read at (branch, tag, or commit SHA). - [JsonPropertyName("ref")] - public required string Ref { get; set; } + /// Optional user-facing message describing the completed command. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Repository the file lives in. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Optional target session mode applied without submitting an agent prompt. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mode")] + public SessionMode? Mode { get; set; } - /// URL to the snippet on GitHub (with line anchor). - [JsonPropertyName("url")] - public required string Url { get; set; } + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Blob attachment with inline base64-encoded data. -/// The blob variant of . +/// Selectable slash-command subcommand option with name, description, and optional group label. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentBlob : PushAttachment +public sealed class SlashCommandSelectSubcommandOption { - /// - [JsonIgnore] - public override string Type => "blob"; - - /// Base64-encoded content. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Human-readable description of the subcommand. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// User-facing display name for the attachment. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } + /// Optional group label for organizing options. + [JsonPropertyName("group")] + public string? Group { get; set; } - /// MIME type of the inline data. - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// Subcommand name to invoke. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Slim input shape for extension_context attachments; identity fields are runtime-derived. -/// The extension_context variant of . +/// Slash-command invocation result asking the client to present subcommand options for a parent command. +/// The select-subcommand variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentExtensionContext : PushAttachment +public partial class SlashCommandInvocationResultSelectSubcommand : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "extension_context"; + public override string Kind => "select-subcommand"; - /// Caller-supplied JSON payload (required, may be null but not undefined). - [JsonPropertyName("payload")] - public required JsonElement Payload { get; set; } + /// Parent command name that requires subcommand selection. + [JsonPropertyName("command")] + public required string Command { 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)] + /// Available subcommand options for the client to present. + [JsonPropertyName("options")] + public required IList Options { get; set; } + + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } + + /// Human-readable title for the selection UI. [JsonPropertyName("title")] public required string Title { get; set; } } -/// Parameters for session.extensions.sendAttachmentsToMessage. +/// RPC data type for SlashCommandTimelineEntry operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendAttachmentsToMessageParams +public sealed class SlashCommandTimelineEntry { - /// 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; } + /// What the user must do to recover, when the entry reports a failure the runtime knows an action for. The `text` never names a client affordance, so a client that offers one renders it from this value. + [JsonPropertyName("remediation")] + public RemediationAction? Remediation { get; 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; } + /// Text displayed for the timeline entry. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Timeline entry presentation type. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + + /// Optional URL associated with the timeline entry. + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// A tool name and arguments to execute through the session's native invocation pipeline. +/// The add-timeline-entry variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsExecuteRequest +public partial class SlashCommandInvocationResultAddTimelineEntry : SlashCommandInvocationResult { - /// Arguments supplied to the tool. - [JsonPropertyName("arguments")] - public JsonElement Arguments { get; set; } + /// + [JsonIgnore] + public override string Kind => "add-timeline-entry"; - /// Name of the currently offered tool to execute. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Timeline entry the host should append. + [JsonPropertyName("entry")] + public required SlashCommandTimelineEntry Entry { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional text the host should prefill into the input editor. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("prefillInput")] + public string? PrefillInput { get; set; } - /// Optional identifier used to correlate this invocation with its tool call. - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + /// Whether command execution changed persisted runtime settings. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Custom grammar input format accepted by a built-in tool. +/// RPC data type for SlashCommandModelPickerDialog operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltinToolFormat +public sealed class SlashCommandModelPickerDialog { - /// Grammar definition accepted by the tool. - [JsonPropertyName("definition")] - public string Definition { get; set; } = string.Empty; + /// Discriminator for a model-picker dialog. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; - /// Grammar syntax used by the format definition. - [JsonPropertyName("syntax")] - public string Syntax { get; set; } = string.Empty; + /// Model that should be enabled before it can be selected. + [JsonPropertyName("modelToEnable")] + public string? ModelToEnable { get; set; } - /// Custom input-format discriminator. - [JsonPropertyName("type")] - public BuiltinToolFormatType Type { get; set; } + /// Settings scope the picker should modify. + [JsonPropertyName("scope")] + public string? Scope { get; set; } + + /// Model-selection target represented by the picker. + [JsonPropertyName("target")] + public string? Target { get; set; } } -/// JSON Schema object accepted by a built-in tool. +/// The show-dialog variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltinToolInputSchema +public partial class SlashCommandInvocationResultShowDialog : SlashCommandInvocationResult { - /// Root type of the tool input schema. - [JsonPropertyName("type")] - public BuiltinToolInputSchemaType Type { get; set; } + /// + [JsonIgnore] + public override string Kind => "show-dialog"; + + /// Dialog the host should display. + [JsonPropertyName("dialog")] + public required SlashCommandModelPickerDialog Dialog { get; set; } + + /// Whether command execution changed persisted runtime settings. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Rust-owned metadata and input schema for a built-in tool. +/// The set-model variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltinToolDescriptor +public partial class SlashCommandInvocationResultSetModel : SlashCommandInvocationResult { - /// Model-facing description of the tool's behavior. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Optional custom input format used instead of a JSON Schema. - [JsonPropertyName("format")] - public BuiltinToolFormat? Format { get; set; } - - /// Whether the tool provides a specialized intention summary. - [JsonPropertyName("hasSummariseIntention")] - public bool HasSummariseIntention { get; set; } + /// + [JsonIgnore] + public override string Kind => "set-model"; - /// JSON Schema for the tool input, or null when the tool uses a custom format. - [JsonPropertyName("inputSchema")] - public BuiltinToolInputSchema? InputSchema { get; set; } + /// Auto routing profile selected by the command, when the model is Auto. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Optional supplemental usage instructions for the tool. - [JsonPropertyName("instructions")] - public string? Instructions { get; set; } + /// Model selected by the command. + [JsonPropertyName("model")] + public required string Model { get; set; } - /// Whether the tool executes commands in a terminal. - [JsonPropertyName("isTerminal")] - public bool IsTerminal { get; set; } + /// Reasoning effort selected for the model. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Stable name used to invoke the built-in tool. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Repository settings scope modified by the command. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("repoScope")] + public string? RepoScope { get; set; } - /// Policy describing which tool metadata may be recorded without obfuscation. - [JsonPropertyName("safeForTelemetry")] - public JsonElement SafeForTelemetry { get; set; } + /// User-settings snapshot to restore if the host cancels the model switch. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("revertOnCancel")] + public IDictionary? RevertOnCancel { get; set; } - /// Optional human-readable title for the tool. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Whether command execution changed persisted runtime settings. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } - /// Optional tool category discriminator. - [JsonPropertyName("type")] - public string? Type { get; set; } -} + /// Settings scope modified by the command. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("scope")] + public string? Scope { get; set; } -/// Rust-owned built-in tool descriptors for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsGetBuiltinDescriptorsResult -{ - /// Built-in tool descriptors materialized for the session. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } + /// User-facing warning produced while selecting the model. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Shell-specific names and description lines used to materialize built-in shell tool descriptors. +/// The set-plan-model variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsShellDescriptorConfig +public partial class SlashCommandInvocationResultSetPlanModel : SlashCommandInvocationResult { - /// Additional model-facing shell description lines. - [JsonPropertyName("descriptionLines")] - public IList DescriptionLines { get => field ??= []; set; } - - /// Human-readable shell name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; - - /// Tool name used to list active shells. - [JsonPropertyName("listShellsToolName")] - public string ListShellsToolName { get; set; } = string.Empty; - - /// Tool name used to read shell output. - [JsonPropertyName("readShellToolName")] - public string ReadShellToolName { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "set-plan-model"; - /// Tool name used to start shell commands. - [JsonPropertyName("shellToolName")] - public string ShellToolName { get; set; } = string.Empty; + /// User-facing confirmation message for the plan-model selection. + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Stable shell type identifier. - [JsonPropertyName("shellType")] - public string ShellType { get; set; } = string.Empty; + /// Dedicated model selected for plan mode. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("planModel")] + public string? PlanModel { get; set; } - /// Tool name used to stop shell commands. - [JsonPropertyName("stopShellToolName")] - public string StopShellToolName { get; set; } = string.Empty; + /// Whether command execution changed persisted runtime settings. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Options controlling how Rust-owned built-in tool descriptors are materialized. +/// Slash command name and optional raw input string to invoke. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsGetBuiltinDescriptorsRequest +internal sealed class CommandsInvokeRequest { - /// Whether background task completion notifications are enabled. - [JsonPropertyName("backgroundTaskNotificationsEnabled")] - public bool? BackgroundTaskNotificationsEnabled { get; set; } + /// Raw input after the command name. + [JsonPropertyName("input")] + public string? Input { get; set; } - /// Whether tool descriptors should include authoring metadata. - [JsonPropertyName("includeAuthor")] - public bool? IncludeAuthor { get; set; } + /// Command name. Leading slashes are stripped and the name is matched case-insensitively. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Whether descriptors should favor fewer user-intervention prompts. - [JsonPropertyName("reduceUserIntervention")] - public bool? ReduceUserIntervention { get; set; } + /// Optional client surface that initiated the invocation. + [JsonPropertyName("origin")] + public CommandsInvocationOrigin? Origin { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; +} - /// Shell-specific names and description lines for shell tools. - [JsonPropertyName("shellConfig")] - public ToolsShellDescriptorConfig? ShellConfig { get; set; } - - /// Whether the configured shell supports PowerShell 7 syntax. - [JsonPropertyName("shellSupportsPowerShell7Syntax")] - public bool? ShellSupportsPowerShell7Syntax { get; set; } - - /// Default shell timeout in milliseconds. - [JsonPropertyName("shellTimeoutMs")] - public double? ShellTimeoutMs { get; set; } +/// Whether finalizing the invocation effect succeeded, and the failure reason when it did not. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class CommandsFinalizeInvocationEffectResult +{ + /// Failure reason when the invocation effect could not be finalized. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Whether semantic skill lookup is available. - [JsonPropertyName("skillEmbeddingEnabled")] - public bool? SkillEmbeddingEnabled { get; set; } + /// Whether the pending invocation effect was finalized successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Task completion notification with summary from the agent. +/// The pending slash-command invocation effect to finalize, plus whether the host applied or cancelled it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskCompleteData +internal sealed class CommandsFinalizeInvocationEffectRequest { - /// Structured blocker details when outcome is blocked. - [JsonPropertyName("blocker")] - public TaskBlocker? Blocker { get; set; } - - /// Active autopilot objective ID evaluated by the completion reviewer. - [JsonPropertyName("objectiveId")] - public long? ObjectiveId { get; set; } + /// The slash-command result object that produced the pending effect, echoed back unchanged. + [JsonPropertyName("effect")] + public IDictionary Effect { get => field ??= new Dictionary(); set; } - /// Semantic completion decision. Absent on legacy events and invalid tool calls. + /// Whether the host applied or cancelled the pending invocation effect. [JsonPropertyName("outcome")] - public TaskCompletionOutcome? Outcome { get; set; } + public CommandsInvocationEffectOutcome Outcome { get; set; } - /// Label-safe runtime rationale for the completion decision (e.g. a cancellation or pause/resume downgrade), when one applies. Reviewer-authored rationale is intentionally omitted here because this event has no IFC label channel; the reviewer's findings remain available through its own labeled sub-agent events. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether the task was accepted as complete. False when validation failed or completion was rejected or blocked by the reviewer. +/// Indicates whether the pending client-handled command was completed successfully. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CommandsHandlePendingCommandResult +{ + /// Whether the command was handled successfully. [JsonPropertyName("success")] - public bool? Success { get; set; } - - /// Summary of the completed task, provided by the agent. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + public bool Success { get; set; } } -/// Binary result returned by a tool for the model. +/// Pending command request ID and an optional error if the client handler failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExternalToolTextResultForLlmBinaryResultsForLlm +internal sealed class CommandsHandlePendingCommandRequest { - /// Base64-encoded binary data. - [Base64String] - [JsonPropertyName("data")] - public string Data { get; set; } = string.Empty; - - /// Human-readable description of the binary data. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Optional metadata from the producing tool. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } + /// Error message if the command handler failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// MIME type of the binary data. - [JsonPropertyName("mimeType")] - public string MimeType { get; set; } = string.Empty; + /// Request ID from the command invocation event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. - [JsonPropertyName("type")] - public ExternalToolTextResultForLlmBinaryResultsForLlmType Type { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A content block within a tool result, which may be text, terminal output, image, audio, or a resource. -/// Polymorphic base type discriminated by type. +/// Error message produced while executing the command, if any. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentText), "text")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentTerminal), "terminal")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentShellExit), "shell_exit")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentImage), "image")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentAudio), "audio")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResourceLink), "resource_link")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResource), "resource")] -public partial class ExternalToolTextResultForLlmContent +public sealed class ExecuteCommandResult { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + /// Error message produced while executing the command, if any. Omitted when the handler succeeded. + [JsonPropertyName("error")] + public string? Error { get; set; } } - -/// Plain text content block. -/// The text variant of . +/// Slash command name and argument string to execute synchronously. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentText : ExternalToolTextResultForLlmContent +internal sealed class ExecuteCommandParams { - /// - [JsonIgnore] - public override string Type => "text"; + /// Argument string to pass to the command (empty string if none). + [JsonPropertyName("args")] + public string Args { get; set; } = string.Empty; - /// The text content. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Name of the slash command to invoke (without the leading '/'). + [JsonPropertyName("commandName")] + public string CommandName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Terminal/shell output content block with optional exit code and working directory. -/// The terminal variant of . +/// Indicates whether the command was accepted into the local execution queue. +/// Data type discriminated by queued. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentTerminal : ExternalToolTextResultForLlmContent +public partial class EnqueueCommandResult { - /// - [JsonIgnore] - public override string Type => "terminal"; - - /// Working directory where the command was executed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// The boolean discriminator. + [JsonPropertyName("queued")] + public bool Queued { get; set; } - /// Process exit code, if the command has completed. + /// Stable opaque ID of the queued command. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } - - /// Terminal/shell output text. - [JsonPropertyName("text")] - public required string Text { get; set; } + [JsonPropertyName("queueId")] + public string? QueueId { get; set; } } -/// Shell command exit metadata with optional output preview. -/// The shell_exit variant of . +/// Slash-prefixed command string to enqueue for FIFO processing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentShellExit : ExternalToolTextResultForLlmContent +internal sealed class EnqueueCommandParams { - /// - [JsonIgnore] - public override string Type => "shell_exit"; + /// Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO with any in-flight items; if the session is idle, processing kicks off immediately. + [JsonPropertyName("command")] + public string Command { get; set; } = string.Empty; - /// Working directory where the shell command was executed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Optional user-facing text for the queue row. The command string is shown when omitted. + [JsonPropertyName("displayText")] + public string? DisplayText { get; set; } - /// Exit code from the completed shell command. - [JsonPropertyName("exitCode")] - public required long ExitCode { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Path reported in the shell session's filesystem namespace when shell output exceeded the configured large-output threshold. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputFilePath")] - public string? OutputFilePath { get; set; } +/// Indicates whether the queued-command response was matched to a pending request. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CommandsRespondToQueuedCommandResult +{ + /// Whether a pending queued command with the given request ID was found and resolved. False when the request was already resolved, cancelled, or unknown. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// Output associated with this shell command, if available. May be partial, truncated, or a preview; not guaranteed to be full output. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputPreview")] - public string? OutputPreview { get; set; } +/// Result of the queued command execution. +/// Data type discriminated by handled. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class QueuedCommandResult +{ + /// The boolean discriminator. + [JsonPropertyName("handled")] + public bool Handled { get; set; } - /// Whether outputPreview is known to be incomplete or truncated. + /// When true, the runtime will not process subsequent queued commands until a new request comes in. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputTruncated")] - public bool? OutputTruncated { get; set; } - - /// Shell id, as assigned by Copilot runtime. - [JsonPropertyName("shellId")] - public required string ShellId { get; set; } + [JsonPropertyName("stopProcessingQueue")] + public bool? StopProcessingQueue { get; set; } } -/// Image content block with base64-encoded data. -/// The image variant of . +/// Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentImage : ExternalToolTextResultForLlmContent +internal sealed class CommandsRespondToQueuedCommandRequest { - /// - [JsonIgnore] - public override string Type => "image"; + /// Request ID from the `command.queued` event the host is responding to. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Base64-encoded image data. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Result of the queued command execution. + [JsonPropertyName("result")] + public QueuedCommandResult Result { get => field ??= new(); set; } - /// MIME type of the image (e.g., image/png, image/jpeg). - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Audio content block with base64-encoded data. -/// The audio variant of . +/// Telemetry engagement ID for the session, when available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentAudio : ExternalToolTextResultForLlmContent +public sealed class SessionTelemetryEngagement { - /// - [JsonIgnore] - public override string Type => "audio"; - - /// Base64-encoded audio data. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } - - /// MIME type of the audio (e.g., audio/wav, audio/mpeg). - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// Current telemetry engagement ID, when available. + [JsonPropertyName("engagementId")] + public string? EngagementId { get; set; } } -/// Icon image for a resource. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExternalToolTextResultForLlmContentResourceLinkIcon +internal sealed class SessionTelemetryGetEngagementIdRequest { - /// MIME type of the icon image. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } - - /// Available icon sizes (e.g., ['16x16', '32x32']). - [JsonPropertyName("sizes")] - public IList? Sizes { get; set; } - - /// URL or path to the icon image. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; - - /// Theme variant this icon is intended for. - [JsonPropertyName("theme")] - public ExternalToolTextResultForLlmContentResourceLinkIconTheme? Theme { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Resource link content block referencing an external resource. -/// The resource_link variant of . +/// Feature override key/value pairs to attach to subsequent telemetry events from this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentResourceLink : ExternalToolTextResultForLlmContent +internal sealed class TelemetrySetFeatureOverridesRequest { - /// - [JsonIgnore] - public override string Type => "resource_link"; + /// Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. + [JsonPropertyName("features")] + public IDictionary Features { get => field ??= new Dictionary(); set; } - /// Human-readable description of the resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Icons associated with this resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("icons")] - public IList? Icons { get; set; } +/// Completed transient query. Ordered chunks and the terminal outcome are also delivered through `ui.ephemeral_query` session events while it runs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIEphemeralQueryResult +{ + /// Answer returned by the model. + [JsonPropertyName("answer")] + public string Answer { get; set; } = string.Empty; +} - /// MIME type of the resource content. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } +/// Transient question to answer without adding it to conversation history. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIEphemeralQueryRequest +{ + /// Question to answer from the current conversation context. + [JsonPropertyName("question")] + public string Question { get; set; } = string.Empty; - /// Resource name identifier. - [JsonPropertyName("name")] - public required string Name { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Size of the resource in bytes. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("size")] - public long? Size { get; set; } +/// The elicitation response (accept with form values, decline, or cancel). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIElicitationResponse +{ + /// MCP response metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Human-readable display title for the resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } + /// The user's response: accept (submitted), decline (rejected), or cancel (dismissed). + [JsonPropertyName("action")] + public UIElicitationResponseAction Action { get; set; } - /// URI identifying the resource. - [JsonPropertyName("uri")] - public required string Uri { get; set; } + /// The form values submitted by the user (present when action is 'accept'). + [JsonPropertyName("content")] + public IDictionary? Content { get; set; } } -/// Embedded resource content block with inline text or binary data. -/// The resource variant of . +/// JSON Schema describing the form fields to present to the user. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentResource : ExternalToolTextResultForLlmContent +public sealed class UIElicitationSchema { - /// - [JsonIgnore] - public override string Type => "resource"; + /// Form field definitions, keyed by field name. + [JsonPropertyName("properties")] + public IDictionary Properties { get => field ??= new Dictionary(); set; } - /// The embedded resource contents, either text or base64-encoded binary. - [JsonPropertyName("resource")] - public required JsonElement Resource { get; set; } + /// List of required field names. + [JsonPropertyName("required")] + public IList? Required { get; set; } + + /// Schema type indicator (always 'object'). + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; } -/// A message injected by a tool result. +/// Metadata controlling an MCP task's lifetime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolResultNewMessage +public sealed class McpTaskMetadata { - /// Message content to inject after the tool result. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; - - /// Source attributed to the injected message. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Task time-to-live. + [JsonPropertyName("ttl")] + public long? Ttl { get; set; } } -/// RPC data type for TaskCompletionDecision operations. +/// Prompt message and JSON schema describing the form fields to elicit from the user. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskCompletionDecision +internal sealed class UIElicitationRequest { - /// Objective eligibility token captured when the decision was evaluated. - [JsonPropertyName("completionEligibilityToken")] - public long? CompletionEligibilityToken { get; set; } + /// MCP request metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Whether completion was accepted after the reviewer-rejection budget was exhausted. - [JsonPropertyName("completionRejectionBudgetExhausted")] - public bool? CompletionRejectionBudgetExhausted { get; set; } + /// Message describing what information is needed from the user. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Active autopilot objective evaluated by the completion reviewer. - [JsonPropertyName("objectiveId")] - public long? ObjectiveId { get; set; } + /// Elicitation mode. Omitted and form are equivalent for structured elicitation. + [JsonPropertyName("mode")] + public McpElicitationFormMode? Mode { get; set; } - /// Semantic result of evaluating the task completion request. - [JsonPropertyName("outcome")] - public TaskCompletionOutcome Outcome { get; set; } + /// JSON Schema describing the form fields to present to the user. + [JsonPropertyName("requestedSchema")] + public UIElicitationSchema RequestedSchema { get => field ??= new(); set; } - /// Rationale for the completion decision, when one is available. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Whether the rationale was derived from completion-reviewer output. - [JsonPropertyName("reviewerDerived")] - public bool? ReviewerDerived { get; set; } + /// MCP task metadata. + [JsonPropertyName("task")] + public McpTaskMetadata? Task { get; set; } +} - /// Information-flow metadata captured from the completion reviewer. - [JsonPropertyName("reviewerResultMeta")] - public JsonElement? ReviewerResultMeta { get; set; } +/// Indicates whether the elicitation response was accepted; false if it was already resolved by another client. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIElicitationResult +{ + /// Whether the response was accepted. False if the request was already resolved by another client. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Expanded canonical result returned by a session tool. +/// Pending elicitation request ID and the user's response (accept/decline/cancel + form values). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolResultExpanded +internal sealed class UIHandlePendingElicitationRequest { - /// Base64-encoded binary results returned to the model. - [JsonPropertyName("binaryResultsForLlm")] - public IList? BinaryResultsForLlm { get; set; } + /// The unique request ID from the elicitation.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Sources returned by the tool that the model may cite. - [JsonPropertyName("citableSources")] - public IList? CitableSources { get; set; } + /// The elicitation response (accept with form values, decline, or cancel). + [JsonPropertyName("result")] + public UIElicitationResponse Result { get => field ??= new(); set; } - /// Structured content blocks returned to the model. - [JsonPropertyName("contents")] - public IList? Contents { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Error message for an unsuccessful execution. - [JsonPropertyName("error")] - public string? Error { get; set; } +/// Indicates whether the pending UI request was resolved by this call. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIHandlePendingResult +{ + /// True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// Metadata propagated with the tool result, including information-flow labels. - [JsonPropertyName("mcpMeta")] - public IDictionary? McpMeta { get; set; } +/// User response for a pending user-input request, with answer text and whether it was typed freeform. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIUserInputResponse +{ + /// The user's answer text. + [JsonPropertyName("answer")] + public string Answer { get; set; } = string.Empty; - /// Messages to inject after the tool result. - [JsonPropertyName("newMessages")] - public IList? NewMessages { get; set; } + /// True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. + [JsonPropertyName("wasFreeform")] + public bool WasFreeform { get; set; } +} + +/// Request ID of a pending `user_input.requested` event and the user's response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIHandlePendingUserInputRequest +{ + /// The unique request ID from the user_input.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Whether post-tool-use failure hooks have already processed this result. - [JsonPropertyName("postToolUseFailureHooksProcessed")] - public bool? PostToolUseFailureHooksProcessed { get; set; } + /// User response for a pending user-input request, with answer text and whether it was typed freeform. + [JsonPropertyName("response")] + public UIUserInputResponse Response { get => field ??= new(); set; } - /// Execution outcome classification. - [JsonPropertyName("resultType")] - public ToolResultType ResultType { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Detailed log content available for session display. - [JsonPropertyName("sessionLog")] - public string? SessionLog { get; set; } +/// Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIHandlePendingSamplingRequest +{ + /// The unique request ID from the sampling.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Skill invocation metadata produced by the tool. - [JsonPropertyName("skillInvocation")] - public JsonElement? SkillInvocation { get; set; } + /// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. + [JsonPropertyName("response")] + public JsonElement? Response { get; set; } - /// Whether large-output post-processing should be skipped. - [JsonPropertyName("skipLargeOutputProcessing")] - public bool? SkipLargeOutputProcessing { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Structured result content in addition to the model-facing text. - [JsonPropertyName("structuredContent")] - public JsonElement? StructuredContent { get; set; } +/// Request ID of a pending `auto_mode_switch.requested` event and the user's response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIHandlePendingAutoModeSwitchRequest +{ + /// The unique request ID from the auto_mode_switch.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Completion-review decision produced by the task-completion tool. - [JsonPropertyName("taskCompletionDecision")] - public TaskCompletionDecision? TaskCompletionDecision { get; set; } + /// User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). + [JsonPropertyName("response")] + public UIAutoModeSwitchResponse Response { get; set; } - /// Text result returned to the model. - [JsonPropertyName("textResultForLlm")] - public string TextResultForLlm { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Deferred tool names made available by this result. - [JsonPropertyName("toolReferences")] - public IList? ToolReferences { get; set; } +/// The user's selected action for an exhausted session limit. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UISessionLimitsExhaustedResponse +{ + /// Action selected by the user. + [JsonPropertyName("action")] + public UISessionLimitsExhaustedResponseAction Action { get; set; } - /// Tool-specific telemetry payload. - [JsonPropertyName("toolTelemetry")] - public JsonElement? ToolTelemetry { get; set; } + /// AI Credits to add to the current max when action is 'add'. + [JsonPropertyName("additionalAiCredits")] + public double? AdditionalAiCredits { get; set; } - /// Optional UI resource produced by the tool. - [JsonPropertyName("uiResource")] - public JsonElement? UiResource { get; set; } + /// New absolute max AI Credits when action is 'set'. + [JsonPropertyName("maxAiCredits")] + public double? MaxAiCredits { get; set; } } -/// Task-completion tool arguments and final result used to build a label-safe session event payload. +/// Request ID of a pending `session_limits_exhausted.requested` event and the user's selected limit action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsTaskCompleteEventDataRequest +internal sealed class UIHandlePendingSessionLimitsExhaustedRequest { - /// Final expanded result returned by the task_complete tool. - [JsonPropertyName("finalResult")] - public ToolResultExpanded FinalResult { get => field ??= new(); set; } + /// The unique request ID from the session_limits_exhausted.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// The selected session-limit action. + [JsonPropertyName("response")] + public UISessionLimitsExhaustedResponse Response { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Arguments supplied to the completed task_complete tool call. - [JsonPropertyName("toolArgs")] - public JsonElement ToolArgs { get; set; } } -/// Indicates whether the external tool call result was handled successfully. +/// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HandlePendingToolCallResult +public sealed class UIExitPlanModeResponse { - /// Whether the tool call result was handled successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the plan was approved. + [JsonPropertyName("approved")] + public bool Approved { get; set; } + + /// Whether subsequent edits should be auto-approved without confirmation. + [JsonPropertyName("autoApproveEdits")] + public bool? AutoApproveEdits { get; set; } + + /// When true, the agent is instructed to end its turn without starting implementation so the client can restore the session model and auto-submit a fresh implementation turn on it. Set only when a distinct plan configuration (a different model, reasoning effort, or context tier) actually ran the planning turn. + [JsonPropertyName("deferImplementation")] + public bool? DeferImplementation { get; set; } + + /// Feedback from the user when they declined the plan or requested changes. + [JsonPropertyName("feedback")] + public string? Feedback { get; set; } + + /// The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. + [JsonPropertyName("selectedAction")] + public UIExitPlanModeAction? SelectedAction { get; set; } } -/// Pending external tool call request ID, with the tool result or an error describing why it failed. +/// Request ID of a pending `exit_plan_mode.requested` event and the user's response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HandlePendingToolCallRequest +internal sealed class UIHandlePendingExitPlanModeRequest { - /// Error message if the tool call failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Request ID of the pending tool call. + /// The unique request ID from the exit_plan_mode.requested event. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; - /// Tool call result (string or expanded result object). - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + /// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. + [JsonPropertyName("response")] + public UIExitPlanModeResponse Response { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Resolve, build, and validate the runtime tool list for this session. Subagent 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. +/// Register an in-process handler for `auto_mode_switch.requested` events. The 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). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsInitializeAndValidateResult +public sealed class UIRegisterDirectAutoModeSwitchHandlerResult { + /// Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionToolsInitializeAndValidateRequest +internal sealed class SessionUiRegisterDirectAutoModeSwitchHandlerRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Lightweight metadata for a currently initialized session tool. +/// Indicates whether the handle was active and the registration count was decremented. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CurrentToolMetadata +public sealed class UIUnregisterDirectAutoModeSwitchHandlerResult { - /// Whether the tool is loaded on demand via tool search. - [JsonPropertyName("deferLoading")] - public bool? DeferLoading { get; set; } - - /// Tool description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// True if the handle was active and decremented the counter; false if the handle was unknown. + [JsonPropertyName("unregistered")] + public bool Unregistered { get; set; } +} - /// JSON Schema for tool input. - [JsonPropertyName("input_schema")] - public IDictionary? InputSchema { get; set; } +/// Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIUnregisterDirectAutoModeSwitchHandlerRequest +{ + /// Handle previously returned by `registerDirectAutoModeSwitchHandler`. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; - /// MCP server name for MCP-backed tools. - [JsonPropertyName("mcpServerName")] - public string? McpServerName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Raw MCP tool name for MCP-backed tools. - [JsonPropertyName("mcpToolName")] - public string? McpToolName { get; set; } +/// Indicates whether the operation succeeded. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionsConfigureResult +{ + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// Model-facing tool name. +/// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRuleSource +{ + /// Name of the policy source. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Optional MCP/config namespaced tool name. - [JsonPropertyName("namespacedName")] - public string? NamespacedName { get; set; } + /// Type of the policy source. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; } -/// Current lightweight tool metadata snapshot for the session. +/// Single content-exclusion rule supplied to `session.permissions.configure`, with paths, match conditions, and source. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsGetCurrentMetadataResult +public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRule { - /// Current tool metadata, or null when tools have not been initialized yet. - [JsonPropertyName("tools")] - public IList? Tools { get; set; } + /// Conditions of which at least one must match. + [JsonPropertyName("ifAnyMatch")] + public IList? IfAnyMatch { get; set; } + + /// Conditions none of which may match. + [JsonPropertyName("ifNoneMatch")] + public IList? IfNoneMatch { get; set; } + + /// Path patterns covered by this rule. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } + + /// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. + [JsonPropertyName("source")] + public PermissionsConfigureAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } } -/// Identifies the target session. +/// Content-exclusion policy supplied to `session.permissions.configure`, with rules, last-updated data, and scope. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionToolsGetCurrentMetadataRequest +public sealed class PermissionsConfigureAdditionalContentExclusionPolicy +{ + /// Opaque policy update timestamp supplied by the host. + [JsonPropertyName("last_updated_at")] + public JsonElement LastUpdatedAt { get; set; } + + /// Content-exclusion rules to apply. + [JsonPropertyName("rules")] + public IList Rules { get => field ??= []; set; } + + /// Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. + [JsonPropertyName("scope")] + public PermissionsConfigureAdditionalContentExclusionPolicyScope Scope { get; set; } +} + +/// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionPathsConfig +{ + /// Additional directories to allow tool access to (in addition to the session's working directory). Conventional `.github/skills/` and `.github/agents/` definitions under them also join the session catalogs when their subsystem gates are enabled, so supplying a directory is a trust decision for configuration stored there. When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). + [JsonPropertyName("additionalDirectories")] + public IList? AdditionalDirectories { get; set; } + + /// Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. + [JsonPropertyName("includeTempDirectory")] + public bool? IncludeTempDirectory { get; set; } + + /// If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. + [JsonPropertyName("unrestricted")] + public bool? Unrestricted { get; set; } + + /// Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. + [JsonPropertyName("workspacePath")] + public string? WorkspacePath { get; set; } +} + +/// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionRulesSet +{ + /// Rules that auto-approve matching requests. + [JsonPropertyName("approved")] + public IList Approved { get => field ??= []; set; } + + /// Rules that auto-deny matching requests. + [JsonPropertyName("denied")] + public IList Denied { get => field ??= []; set; } +} + +/// 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(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionUrlsConfig +{ + /// Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. + [JsonPropertyName("initialAllowed")] + public IList? InitialAllowed { get; set; } + + /// If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. + [JsonPropertyName("unrestricted")] + public bool? Unrestricted { get; set; } +} + +/// Patch of permission policy fields to apply (omit a field to leave it unchanged). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionsConfigureParams { + /// 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. + [JsonPropertyName("additionalContentExclusionPolicies")] + public IList? AdditionalContentExclusionPolicies { get; set; } + + /// If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. + [JsonPropertyName("approveAllReadPermissionRequests")] + public bool? ApproveAllReadPermissionRequests { get; set; } + + /// If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. + [JsonPropertyName("approveAllToolPermissionRequests")] + public bool? ApproveAllToolPermissionRequests { get; set; } + + /// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. + [JsonPropertyName("paths")] + public PermissionPathsConfig? Paths { get; set; } + + /// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. + [JsonPropertyName("rules")] + public PermissionRulesSet? Rules { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// 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. + [JsonPropertyName("urls")] + public PermissionUrlsConfig? Urls { get; set; } } -/// Empty result after replacing the calling connection's externally implemented tools. +/// Indicates whether the permission decision was applied; false when the request was already resolved. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsSetResult +public sealed class PermissionRequestResult { + /// Whether the permission request was handled successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Serializable definition of a caller-implemented tool whose execution is handled over the SDK connection. +/// The client's response to the pending permission prompt. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolExternalToolDefinition +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(PermissionDecisionApproveOnce), "approve-once")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSession), "approve-for-session")] +[JsonDerivedType(typeof(PermissionDecisionApproveReadOnlyForSession), "approve-read-only-for-session")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocation), "approve-for-location")] +[JsonDerivedType(typeof(PermissionDecisionApprovePermanently), "approve-permanently")] +[JsonDerivedType(typeof(PermissionDecisionReject), "reject")] +[JsonDerivedType(typeof(PermissionDecisionUserNotAvailable), "user-not-available")] +[JsonDerivedType(typeof(PermissionDecisionApproved), "approved")] +[JsonDerivedType(typeof(PermissionDecisionApprovedForSession), "approved-for-session")] +[JsonDerivedType(typeof(PermissionDecisionApprovedForLocation), "approved-for-location")] +[JsonDerivedType(typeof(PermissionDecisionCancelled), "cancelled")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByRules), "denied-by-rules")] +[JsonDerivedType(typeof(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser), "denied-no-approval-rule-and-could-not-request-from-user")] +[JsonDerivedType(typeof(PermissionDecisionDeniedInteractivelyByUser), "denied-interactively-by-user")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByContentExclusionPolicy), "denied-by-content-exclusion-policy")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByPermissionRequestHook), "denied-by-permission-request-hook")] +public partial class PermissionDecision { - /// Tool-loading deferral policy. - [JsonPropertyName("defer")] - public ProtocolExternalToolDefer? Defer { get; set; } - - /// Model-visible explanation of what the tool does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Whether the tool executes commands in a terminal. - [JsonPropertyName("isTerminal")] - public bool? IsTerminal { get; set; } - /// Optional caller-defined metadata associated with the tool. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } +/// Permission-decision request variant to approve only the current permission request. +/// The approve-once variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveOnce : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "approve-once"; - /// Unique model-visible tool name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// True only when a host surfaced this request to a user who approved it. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("approvedInteractively")] + public bool? ApprovedInteractively { get; set; } +} - /// Whether this definition replaces a built-in tool with the same name. - [JsonPropertyName("overridesBuiltInTool")] - public bool? OverridesBuiltInTool { get; set; } +/// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCommands), "commands")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalRead), "read")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWrite), "write")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcp), "mcp")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcpSampling), "mcp-sampling")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMemory), "memory")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCustomTool), "custom-tool")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionManagement), "extension-management")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWorkflow), "workflow")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess), "extension-permission-access")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionEnvAccess), "extension-env-access")] +public partial class PermissionDecisionApproveForSessionApproval +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// JSON Schema describing the tool's input arguments. - [JsonPropertyName("parameters")] - public IDictionary? Parameters { get; set; } - /// Whether execution bypasses the normal tool permission prompt. - [JsonPropertyName("skipPermission")] - public bool? SkipPermission { get; set; } +/// Session-scoped approval details for specific command identifiers. +/// The commands variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalCommands : PermissionDecisionApproveForSessionApproval +{ + /// + [JsonIgnore] + public override string Kind => "commands"; - /// Optional human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Command identifiers covered by this approval. + [JsonPropertyName("commandIdentifiers")] + public required IList CommandIdentifiers { get; set; } } -/// Complete externally implemented tool list for the calling connection. An empty list removes every tool previously supplied by that connection. +/// Session-scoped approval details for read-only filesystem operations. +/// The read variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsSetRequest +public partial class PermissionDecisionApproveForSessionApprovalRead : PermissionDecisionApproveForSessionApproval { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "read"; +} - /// Complete replacement list for the calling connection. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } +/// Session-scoped approval details for filesystem write operations. +/// The write variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalWrite : PermissionDecisionApproveForSessionApproval +{ + /// + [JsonIgnore] + public override string Kind => "write"; } -/// Empty result after applying subagent settings. +/// Session-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsUpdateSubagentSettingsResult +public partial class PermissionDecisionApproveForSessionApprovalMcp : PermissionDecisionApproveForSessionApproval { + /// + [JsonIgnore] + public override string Kind => "mcp"; + + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } + + /// MCP tool name, or null to cover every tool on the server. + [JsonPropertyName("toolName")] + public string? ToolName { get; set; } } -/// Subagent model, reasoning effort, context tier, and auto-invocation settings. +/// Session-scoped approval details for MCP sampling requests from a server. +/// The mcp-sampling variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SubagentSettingsEntry +public partial class PermissionDecisionApproveForSessionApprovalMcpSampling : PermissionDecisionApproveForSessionApproval { - /// Whether this agent's runtime-defined proactive invocation prompting is enabled, if supported. Currently consumed by the built-in rubber-duck agent. - [JsonPropertyName("autoInvoke")] - public bool? AutoInvoke { get; set; } + /// + [JsonIgnore] + public override string Kind => "mcp-sampling"; - /// Context tier override for matching subagents. - [JsonPropertyName("contextTier")] - public SubagentSettingsEntryContextTier? ContextTier { get; set; } + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } +} - /// Reasoning effort override for matching subagents. - [JsonPropertyName("effortLevel")] - public string? EffortLevel { get; set; } +/// Session-scoped approval details for writes to long-term memory. +/// The memory variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalMemory : PermissionDecisionApproveForSessionApproval +{ + /// + [JsonIgnore] + public override string Kind => "memory"; +} - /// Model override for matching subagents. - [JsonPropertyName("model")] - public string? Model { get; set; } +/// Session-scoped approval details for a custom tool, keyed by tool name. +/// The custom-tool variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalCustomTool : PermissionDecisionApproveForSessionApproval +{ + /// + [JsonIgnore] + public override string Kind => "custom-tool"; - /// Whether the configured model strategy is preferred or required. - [JsonPropertyName("modelPolicy")] - public AgentModelPolicy? ModelPolicy { get; set; } + /// Custom tool name. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } -/// Configured per-agent subagent overrides. -public sealed class UpdateSubagentSettingsRequestSubagents +/// Session-scoped approval details for extension-management operations, optionally narrowed by operation. +/// The extension-management variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalExtensionManagement : PermissionDecisionApproveForSessionApproval { - /// Per-agent settings keyed by subagent agent_type. - [JsonPropertyName("agents")] - public IDictionary? Agents { get; set; } + /// + [JsonIgnore] + public override string Kind => "extension-management"; - /// Names of subagents the user has turned off; they cannot be dispatched. - [JsonPropertyName("disabledSubagents")] - public IList? DisabledSubagents { get; set; } + /// Optional operation identifier; when omitted, the approval covers all extension management operations. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("operation")] + public string? Operation { get; set; } +} - /// Maximum number of subagents that can run concurrently; applies to usage-based billing users only. - [JsonPropertyName("maxConcurrency")] - public int? MaxConcurrency { get; set; } +/// Session-scoped workflow approval, optionally narrowed by approval key. +/// The workflow variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalWorkflow : PermissionDecisionApproveForSessionApproval +{ + /// + [JsonIgnore] + public override string Kind => "workflow"; - /// Maximum subagent nesting depth; applies to usage-based billing users only. - [JsonPropertyName("maxDepth")] - public int? MaxDepth { get; set; } + /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("approvalKey")] + public string? ApprovalKey { get; set; } } -/// Subagent settings to apply to the current session. +/// Session-scoped approval details for an extension's permission-gated capability access, keyed by extension name. +/// The extension-permission-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UpdateSubagentSettingsRequest +public partial class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess : PermissionDecisionApproveForSessionApproval { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "extension-permission-access"; - /// Subagent settings to apply, or null to clear the live session override. - [JsonPropertyName("subagents")] - public UpdateSubagentSettingsRequestSubagents? Subagents { get; set; } + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// RPC data type for SessionCommandsList operations. +/// Session-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. +/// The extension-env-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionCommandsListRequest +public partial class PermissionDecisionApproveForSessionApprovalExtensionEnvAccess : PermissionDecisionApproveForSessionApproval { - /// Include runtime built-in commands. - [JsonPropertyName("includeBuiltins")] - public bool? IncludeBuiltins { get; set; } + /// + [JsonIgnore] + public override string Kind => "extension-env-access"; - /// Include commands registered by protocol clients, including SDK clients and extensions. - [JsonPropertyName("includeClientCommands")] - public bool? IncludeClientCommands { get; set; } + /// Names of the sensitive environment variables this approval covers. Values are never persisted. + [JsonPropertyName("environmentVariables")] + public required IList EnvironmentVariables { get; set; } - /// Include enabled user-invocable skills and commands. - [JsonPropertyName("includeSkills")] - public bool? IncludeSkills { get; set; } + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// RPC data type for SessionCommandsListRequestWithSession operations. +/// Permission-decision request variant to approve for the rest of the session, with optional tool approval or URL domain. +/// The approve-for-session variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCommandsListRequestWithSession +public partial class PermissionDecisionApproveForSession : PermissionDecision { - /// Include runtime built-in commands. - [JsonPropertyName("includeBuiltins")] - public bool? IncludeBuiltins { get; set; } + /// + [JsonIgnore] + public override string Kind => "approve-for-session"; - /// Include commands registered by protocol clients, including SDK clients and extensions. - [JsonPropertyName("includeClientCommands")] - public bool? IncludeClientCommands { get; set; } + /// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("approval")] + public PermissionDecisionApproveForSessionApproval? Approval { get; set; } - /// Include enabled user-invocable skills and commands. - [JsonPropertyName("includeSkills")] - public bool? IncludeSkills { get; set; } + /// URL domain to approve for the rest of the session (URL prompts only). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("domain")] + public string? Domain { get; set; } +} - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; +/// Approve file-tool read access to specific directories for this logical session, including continuation or resume. +/// The approve-read-only-for-session variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveReadOnlyForSession : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "approve-read-only-for-session"; + + /// Canonical directories covered by the read-only grant. + [JsonPropertyName("directories")] + public required IList Directories { get; set; } } -/// Result of invoking the slash command (text output, prompt to send to the agent, completion, or subcommand selection). +/// Approval to persist for this location. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SlashCommandInvocationResultText), "text")] -[JsonDerivedType(typeof(SlashCommandInvocationResultAgentPrompt), "agent-prompt")] -[JsonDerivedType(typeof(SlashCommandInvocationResultCompleted), "completed")] -[JsonDerivedType(typeof(SlashCommandInvocationResultSelectSubcommand), "select-subcommand")] -[JsonDerivedType(typeof(SlashCommandInvocationResultAddTimelineEntry), "add-timeline-entry")] -[JsonDerivedType(typeof(SlashCommandInvocationResultShowDialog), "show-dialog")] -[JsonDerivedType(typeof(SlashCommandInvocationResultSetModel), "set-model")] -[JsonDerivedType(typeof(SlashCommandInvocationResultSetPlanModel), "set-plan-model")] -public partial class SlashCommandInvocationResult +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCommands), "commands")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalRead), "read")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWrite), "write")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcp), "mcp")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcpSampling), "mcp-sampling")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMemory), "memory")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCustomTool), "custom-tool")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionManagement), "extension-management")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWorkflow), "workflow")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess), "extension-permission-access")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionEnvAccess), "extension-env-access")] +public partial class PermissionDecisionApproveForLocationApproval { /// The type discriminator. [JsonPropertyName("kind")] @@ -20429,822 +25094,630 @@ public partial class SlashCommandInvocationResult } -/// Slash-command invocation result containing text output plus Markdown/ANSI rendering flags. -/// The text variant of . +/// Location-scoped approval details for specific command identifiers. +/// The commands variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultText : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocationApprovalCommands : PermissionDecisionApproveForLocationApproval { /// [JsonIgnore] - public override string Kind => "text"; - - /// Whether text contains Markdown. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("markdown")] - public bool? Markdown { get; set; } - - /// Whether ANSI sequences should be preserved. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("preserveAnsi")] - public bool? PreserveAnsi { get; set; } - - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } - - /// Present when the invocation changed the sandbox for this session only. Nothing was persisted, so consumers must mirror the change onto the live session rather than reloading settings, and must not treat it as a settings change. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("sandboxSessionChange")] - public SandboxSessionChange? SandboxSessionChange { get; set; } + public override string Kind => "commands"; - /// Text output for the client to render. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Command identifiers covered by this approval. + [JsonPropertyName("commandIdentifiers")] + public required IList CommandIdentifiers { get; set; } } -/// Slash-command invocation result that submits an agent prompt, with display prompt, optional mode, optional user-facing notice, and settings-change flag. -/// The agent-prompt variant of . +/// Location-scoped approval details for read-only filesystem operations. +/// The read variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultAgentPrompt : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocationApprovalRead : PermissionDecisionApproveForLocationApproval { /// [JsonIgnore] - public override string Kind => "agent-prompt"; - - /// Prompt text to display to the user. - [JsonPropertyName("displayPrompt")] - public required string DisplayPrompt { get; set; } - - /// Optional target session mode for the agent prompt. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mode")] - public SessionMode? Mode { get; set; } - - /// Optional user-facing notice to show before the prompt is submitted. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("notice")] - public string? Notice { get; set; } - - /// Prompt to submit to the agent. - [JsonPropertyName("prompt")] - public required string Prompt { get; set; } - - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "read"; } -/// Slash-command invocation result indicating completion, with optional message and settings-change flag. -/// The completed variant of . +/// Location-scoped approval details for filesystem write operations. +/// The write variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultCompleted : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocationApprovalWrite : PermissionDecisionApproveForLocationApproval { /// [JsonIgnore] - public override string Kind => "completed"; - - /// Optional user-facing message describing the completed command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } - - /// Optional target session mode applied without submitting an agent prompt. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mode")] - public SessionMode? Mode { get; set; } - - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "write"; } -/// Selectable slash-command subcommand option with name, description, and optional group label. +/// Location-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandSelectSubcommandOption +public partial class PermissionDecisionApproveForLocationApprovalMcp : PermissionDecisionApproveForLocationApproval { - /// Human-readable description of the subcommand. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "mcp"; - /// Optional group label for organizing options. - [JsonPropertyName("group")] - public string? Group { get; set; } + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } - /// Subcommand name to invoke. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// MCP tool name, or null to cover every tool on the server. + [JsonPropertyName("toolName")] + public string? ToolName { get; set; } } -/// Slash-command invocation result asking the client to present subcommand options for a parent command. -/// The select-subcommand variant of . +/// Location-scoped approval details for MCP sampling requests from a server. +/// The mcp-sampling variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultSelectSubcommand : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocationApprovalMcpSampling : PermissionDecisionApproveForLocationApproval { /// [JsonIgnore] - public override string Kind => "select-subcommand"; - - /// Parent command name that requires subcommand selection. - [JsonPropertyName("command")] - public required string Command { get; set; } - - /// Available subcommand options for the client to present. - [JsonPropertyName("options")] - public required IList Options { get; set; } - - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "mcp-sampling"; - /// Human-readable title for the selection UI. - [JsonPropertyName("title")] - public required string Title { get; set; } + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// RPC data type for SlashCommandTimelineEntry operations. +/// Location-scoped approval details for writes to long-term memory. +/// The memory variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandTimelineEntry +public partial class PermissionDecisionApproveForLocationApprovalMemory : PermissionDecisionApproveForLocationApproval { - /// What the user must do to recover, when the entry reports a failure the runtime knows an action for. The `text` never names a client affordance, so a client that offers one renders it from this value. - [JsonPropertyName("remediation")] - public RemediationAction? Remediation { get; set; } - - /// Text displayed for the timeline entry. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; - - /// Timeline entry presentation type. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; - - /// Optional URL associated with the timeline entry. - [JsonPropertyName("url")] - public string? Url { get; set; } + /// + [JsonIgnore] + public override string Kind => "memory"; } -/// The add-timeline-entry variant of . +/// Location-scoped approval details for a custom tool, keyed by tool name. +/// The custom-tool variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultAddTimelineEntry : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocationApprovalCustomTool : PermissionDecisionApproveForLocationApproval { /// [JsonIgnore] - public override string Kind => "add-timeline-entry"; - - /// Timeline entry the host should append. - [JsonPropertyName("entry")] - public required SlashCommandTimelineEntry Entry { get; set; } - - /// Optional text the host should prefill into the input editor. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("prefillInput")] - public string? PrefillInput { get; set; } + public override string Kind => "custom-tool"; - /// Whether command execution changed persisted runtime settings. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + /// Custom tool name. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } -/// RPC data type for SlashCommandModelPickerDialog operations. +/// Location-scoped approval details for extension-management operations, optionally narrowed by operation. +/// The extension-management variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandModelPickerDialog +public partial class PermissionDecisionApproveForLocationApprovalExtensionManagement : PermissionDecisionApproveForLocationApproval { - /// Discriminator for a model-picker dialog. - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; - - /// Model that should be enabled before it can be selected. - [JsonPropertyName("modelToEnable")] - public string? ModelToEnable { get; set; } - - /// Settings scope the picker should modify. - [JsonPropertyName("scope")] - public string? Scope { get; set; } + /// + [JsonIgnore] + public override string Kind => "extension-management"; - /// Model-selection target represented by the picker. - [JsonPropertyName("target")] - public string? Target { get; set; } + /// Optional operation identifier; when omitted, the approval covers all extension management operations. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("operation")] + public string? Operation { get; set; } } -/// The show-dialog variant of . +/// Location-scoped workflow approval, optionally narrowed by approval key. +/// The workflow variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultShowDialog : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocationApprovalWorkflow : PermissionDecisionApproveForLocationApproval { /// [JsonIgnore] - public override string Kind => "show-dialog"; - - /// Dialog the host should display. - [JsonPropertyName("dialog")] - public required SlashCommandModelPickerDialog Dialog { get; set; } + public override string Kind => "workflow"; - /// Whether command execution changed persisted runtime settings. + /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + [JsonPropertyName("approvalKey")] + public string? ApprovalKey { get; set; } } -/// User-settings snapshot to restore if the host cancels the model switch. -public sealed class SlashCommandInvocationResultSetModelRevertOnCancel +/// Location-scoped approval details for an extension's permission-gated capability access, keyed by extension name. +/// The extension-permission-access variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess : PermissionDecisionApproveForLocationApproval { + /// + [JsonIgnore] + public override string Kind => "extension-permission-access"; + + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// The set-model variant of . +/// Location-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. +/// The extension-env-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultSetModel : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocationApprovalExtensionEnvAccess : PermissionDecisionApproveForLocationApproval { /// [JsonIgnore] - public override string Kind => "set-model"; - - /// Auto routing profile selected by the command, when the model is Auto. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// Model selected by the command. - [JsonPropertyName("model")] - public required string Model { get; set; } - - /// Reasoning effort selected for the model. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } - - /// Repository settings scope modified by the command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("repoScope")] - public string? RepoScope { get; set; } - - /// User-settings snapshot to restore if the host cancels the model switch. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("revertOnCancel")] - public SlashCommandInvocationResultSetModelRevertOnCancel? RevertOnCancel { get; set; } - - /// Whether command execution changed persisted runtime settings. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "extension-env-access"; - /// Settings scope modified by the command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("scope")] - public string? Scope { get; set; } + /// Names of the sensitive environment variables this approval covers. Values are never persisted. + [JsonPropertyName("environmentVariables")] + public required IList EnvironmentVariables { get; set; } - /// User-facing warning produced while selecting the model. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("warning")] - public string? Warning { get; set; } + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// The set-plan-model variant of . +/// Permission-decision request variant to approve and persist a permission for a project location, with approval details and location key. +/// The approve-for-location variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultSetPlanModel : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForLocation : PermissionDecision { /// [JsonIgnore] - public override string Kind => "set-plan-model"; - - /// User-facing confirmation message for the plan-model selection. - [JsonPropertyName("message")] - public required string Message { get; set; } + public override string Kind => "approve-for-location"; - /// Dedicated model selected for plan mode. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("planModel")] - public string? PlanModel { get; set; } + /// Approval to persist for this location. + [JsonPropertyName("approval")] + public required PermissionDecisionApproveForLocationApproval Approval { get; set; } - /// Whether command execution changed persisted runtime settings. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + /// Location key (git root or cwd) to persist the approval to. + [JsonPropertyName("locationKey")] + public required string LocationKey { get; set; } } -/// Slash command name and optional raw input string to invoke. +/// Permission-decision request variant to permanently approve a URL domain across sessions. +/// The approve-permanently variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsInvokeRequest +public partial class PermissionDecisionApprovePermanently : PermissionDecision { - /// Raw input after the command name. - [JsonPropertyName("input")] - public string? Input { get; set; } + /// + [JsonIgnore] + public override string Kind => "approve-permanently"; - /// Command name. Leading slashes are stripped and the name is matched case-insensitively. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// URL domain to approve permanently. + [JsonPropertyName("domain")] + public required string Domain { get; set; } +} - /// Optional client surface that initiated the invocation. - [JsonPropertyName("origin")] - public CommandsInvocationOrigin? Origin { get; set; } +/// Permission-decision request variant to reject a pending permission request, with optional feedback. +/// The reject variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionReject : PermissionDecision +{ + /// + [JsonIgnore] + public override string Kind => "reject"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional feedback explaining the rejection. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("feedback")] + public string? Feedback { get; set; } } -/// Whether finalizing the invocation effect succeeded, and the failure reason when it did not. +/// Permission-decision variant indicating no user was available to confirm the request. +/// The user-not-available variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsFinalizeInvocationEffectResult +public partial class PermissionDecisionUserNotAvailable : PermissionDecision { - /// Failure reason when the invocation effect could not be finalized. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Whether the pending invocation effect was finalized successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// + [JsonIgnore] + public override string Kind => "user-not-available"; } -/// The slash-command result object that produced the pending effect, echoed back unchanged. -public sealed class CommandsFinalizeInvocationEffectRequestEffect +/// Permission-decision variant indicating the request was approved. +/// The approved variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproved : PermissionDecision { + /// + [JsonIgnore] + public override string Kind => "approved"; } -/// The pending slash-command invocation effect to finalize, plus whether the host applied or cancelled it. +/// Permission-decision variant indicating approval was remembered for the session, with approval details. +/// The approved-for-session variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsFinalizeInvocationEffectRequest +public partial class PermissionDecisionApprovedForSession : PermissionDecision { - /// The slash-command result object that produced the pending effect, echoed back unchanged. - [JsonPropertyName("effect")] - public CommandsFinalizeInvocationEffectRequestEffect Effect { get => field ??= new(); set; } - - /// Whether the host applied or cancelled the pending invocation effect. - [JsonPropertyName("outcome")] - public CommandsInvocationEffectOutcome Outcome { get; set; } + /// + [JsonIgnore] + public override string Kind => "approved-for-session"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The approval to add as a session-scoped rule. + [JsonPropertyName("approval")] + public required UserToolSessionApproval Approval { get; set; } } -/// Indicates whether the pending client-handled command was completed successfully. +/// Permission-decision variant indicating approval was persisted for a project location, with approval details and location key. +/// The approved-for-location variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CommandsHandlePendingCommandResult +public partial class PermissionDecisionApprovedForLocation : PermissionDecision { - /// Whether the command was handled successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// + [JsonIgnore] + public override string Kind => "approved-for-location"; + + /// The approval to persist for this location. + [JsonPropertyName("approval")] + public required UserToolSessionApproval Approval { get; set; } + + /// The location key (git root or cwd) to persist the approval to. + [JsonPropertyName("locationKey")] + public required string LocationKey { get; set; } } -/// Pending command request ID and an optional error if the client handler failed. +/// Permission-decision variant indicating the request was cancelled before use, with an optional reason. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsHandlePendingCommandRequest +public partial class PermissionDecisionCancelled : PermissionDecision { - /// Error message if the command handler failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Request ID from the command invocation event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "cancelled"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional explanation of why the request was cancelled. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reason")] + public string? Reason { get; set; } } -/// Error message produced while executing the command, if any. +/// Permission-decision variant indicating explicit denial by permission rules, with the matching rules. +/// The denied-by-rules variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExecuteCommandResult +public partial class PermissionDecisionDeniedByRules : PermissionDecision { - /// Error message produced while executing the command, if any. Omitted when the handler succeeded. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// + [JsonIgnore] + public override string Kind => "denied-by-rules"; + + /// Rules that denied the request. + [JsonPropertyName("rules")] + public required IList Rules { get; set; } } -/// Slash command name and argument string to execute synchronously. +/// Permission-decision variant indicating no approval rule matched and user confirmation was unavailable. +/// The denied-no-approval-rule-and-could-not-request-from-user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ExecuteCommandParams +public partial class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser : PermissionDecision { - /// Argument string to pass to the command (empty string if none). - [JsonPropertyName("args")] - public string Args { get; set; } = string.Empty; - - /// Name of the slash command to invoke (without the leading '/'). - [JsonPropertyName("commandName")] - public string CommandName { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "denied-no-approval-rule-and-could-not-request-from-user"; } -/// Indicates whether the command was accepted into the local execution queue. -/// Data type discriminated by queued. +/// Permission-decision variant indicating the user denied an interactive prompt, with optional feedback and force-reject flag. +/// The denied-interactively-by-user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class EnqueueCommandResult +public partial class PermissionDecisionDeniedInteractivelyByUser : PermissionDecision { - /// The boolean discriminator. - [JsonPropertyName("queued")] - public bool Queued { get; set; } + /// + [JsonIgnore] + public override string Kind => "denied-interactively-by-user"; - /// Stable opaque ID of the queued command. + /// Optional feedback from the user explaining the denial. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("queueId")] - public string? QueueId { get; set; } + [JsonPropertyName("feedback")] + public string? Feedback { get; set; } + + /// Whether to force-reject the current agent turn. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("forceReject")] + public bool? ForceReject { get; set; } } -/// Slash-prefixed command string to enqueue for FIFO processing. +/// Permission-decision variant indicating denial by content-exclusion policy, with path and message. +/// The denied-by-content-exclusion-policy variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnqueueCommandParams +public partial class PermissionDecisionDeniedByContentExclusionPolicy : PermissionDecision { - /// Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO with any in-flight items; if the session is idle, processing kicks off immediately. - [JsonPropertyName("command")] - public string Command { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "denied-by-content-exclusion-policy"; - /// Optional user-facing text for the queue row. The command string is shown when omitted. - [JsonPropertyName("displayText")] - public string? DisplayText { get; set; } + /// Human-readable explanation of why the path was excluded. + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// File path that triggered the exclusion. + [JsonPropertyName("path")] + public required string Path { get; set; } } -/// Indicates whether the queued-command response was matched to a pending request. +/// Permission-decision variant indicating denial by a permission request hook, with optional message and interrupt flag. +/// The denied-by-permission-request-hook variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CommandsRespondToQueuedCommandResult +public partial class PermissionDecisionDeniedByPermissionRequestHook : PermissionDecision { - /// Whether a pending queued command with the given request ID was found and resolved. False when the request was already resolved, cancelled, or unknown. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// + [JsonIgnore] + public override string Kind => "denied-by-permission-request-hook"; -/// Result of the queued command execution. -/// Data type discriminated by handled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class QueuedCommandResult -{ - /// The boolean discriminator. - [JsonPropertyName("handled")] - public bool Handled { get; set; } + /// Whether to interrupt the current agent turn. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("interrupt")] + public bool? Interrupt { get; set; } - /// When true, the runtime will not process subsequent queued commands until a new request comes in. + /// Optional message from the hook explaining the denial. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("stopProcessingQueue")] - public bool? StopProcessingQueue { get; set; } + [JsonPropertyName("message")] + public string? Message { get; set; } } -/// Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). +/// Pending permission request ID and the decision to apply (approve/reject and scope). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsRespondToQueuedCommandRequest +internal sealed class PermissionDecisionRequest { - /// Request ID from the `command.queued` event the host is responding to. + /// Optional informational context describing how and where this response was made. Omit it to preserve legacy behavior without attributing an origin. + [JsonPropertyName("decisionContext")] + public PermissionDecisionContext? DecisionContext { get; set; } + + /// Request ID of the pending permission request. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; - /// Result of the queued command execution. + /// The client's response to the pending permission prompt. [JsonPropertyName("result")] - public QueuedCommandResult Result { get => field ??= new(); set; } + public PermissionDecision Result { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Telemetry engagement ID for the session, when available. +/// Pending permission prompt reconstructed from event history, with request ID and user-facing prompt details. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionTelemetryEngagement +public sealed class PendingPermissionRequest { - /// Current telemetry engagement ID, when available. - [JsonPropertyName("engagementId")] - public string? EngagementId { get; set; } + /// Permission-recovery episode that authorized this request to surface for interactive attention. + [JsonPropertyName("recoveryEpisodeId")] + public string? RecoveryEpisodeId { get; set; } + + /// The user-facing permission prompt details (commands, write, read, mcp, url, memory, custom-tool, path, hook). + [JsonPropertyName("request")] + public PermissionPromptRequest Request { get; set; } = null!; + + /// Unique identifier for the pending permission request. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; } -/// Identifies the target session. +/// List of pending permission requests reconstructed from event history. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTelemetryGetEngagementIdRequest +public sealed class PendingPermissionRequestList { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } } -/// Feature override key/value pairs to attach to subsequent telemetry events from this session. +/// No parameters; returns currently-pending permission requests for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TelemetrySetFeatureOverridesRequest +internal sealed class PermissionsPendingRequestsRequest { - /// Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. - [JsonPropertyName("features")] - public IDictionary Features { get => field ??= new Dictionary(); set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Completed transient query. Ordered chunks and the terminal outcome are also delivered through `ui.ephemeral_query` session events while it runs. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIEphemeralQueryResult +public sealed class PermissionsSetApproveAllResult { - /// Answer returned by the model. - [JsonPropertyName("answer")] - public string Answer { get; set; } = string.Empty; + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Transient question to answer without adding it to conversation history. +/// Allow-all toggle for tool permission requests, with an optional telemetry source. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIEphemeralQueryRequest +internal sealed class PermissionsSetApproveAllRequest { - /// Question to answer from the current conversation context. - [JsonPropertyName("question")] - public string Question { get; set; } = string.Empty; + /// Whether to auto-approve all tool permission requests. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} - -/// The elicitation response (accept with form values, decline, or cancel). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIElicitationResponse -{ - /// MCP response metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// The user's response: accept (submitted), decline (rejected), or cancel (dismissed). - [JsonPropertyName("action")] - public UIElicitationResponseAction Action { get; set; } - /// The form values submitted by the user (present when action is 'accept'). - [JsonPropertyName("content")] - public IDictionary? Content { get; set; } + /// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers. + [JsonPropertyName("source")] + public PermissionsSetApproveAllSource? Source { get; set; } } -/// JSON Schema describing the form fields to present to the user. +/// Indicates whether the requested permission mode was applied and reports the authoritative post-mutation mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIElicitationSchema +public sealed class PermissionsSetModeResult { - /// Form field definitions, keyed by field name. - [JsonPropertyName("properties")] - public IDictionary Properties { get => field ??= new Dictionary(); set; } - - /// List of required field names. - [JsonPropertyName("required")] - public IList? Required { get; set; } - - /// Schema type indicator (always 'object'). - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; -} + /// Authoritative permission mode after the mutation. + [JsonPropertyName("mode")] + public PermissionMode Mode { get; set; } -/// Metadata controlling an MCP task's lifetime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpTaskMetadata -{ - /// Task time-to-live. - [JsonPropertyName("ttl")] - public long? Ttl { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Prompt message and JSON schema describing the form fields to elicit from the user. +/// Permission mode to apply for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIElicitationRequest +internal sealed class PermissionsSetModeRequest { - /// MCP request metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Message describing what information is needed from the user. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Optional judge model id for assisted mode. When omitted, the session resolves the provider default: `gpt-5.5` for CAPI sessions and the active session model for BYOK sessions. + [JsonPropertyName("assistedApprovalModel")] + public string? AssistedApprovalModel { get; set; } - /// Elicitation mode. Omitted and form are equivalent for structured elicitation. + /// Permission mode to apply. [JsonPropertyName("mode")] - public McpElicitationFormMode? Mode { get; set; } - - /// JSON Schema describing the form fields to present to the user. - [JsonPropertyName("requestedSchema")] - public UIElicitationSchema RequestedSchema { get => field ??= new(); set; } + public PermissionMode Mode { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// MCP task metadata. - [JsonPropertyName("task")] - public McpTaskMetadata? Task { get; set; } + /// Optional source for permission-mode telemetry. `organization_targeting` is reserved for startup selection after the authenticated account matches an organization targeting policy; SDK callers default to `rpc` and cannot claim targeting provenance. + [JsonPropertyName("source")] + public PermissionModeSource? Source { get; set; } } -/// Indicates whether the elicitation response was accepted; false if it was already resolved by another client. +/// Current permission mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIElicitationResult +public sealed class PermissionsGetModeResult { - /// Whether the response was accepted. False if the request was already resolved by another client. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Current permission mode. + [JsonPropertyName("mode")] + public PermissionMode Mode { get; set; } } -/// Pending elicitation request ID and the user's response (accept/decline/cancel + form values). +/// No parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingElicitationRequest +internal sealed class PermissionsGetModeRequest { - /// The unique request ID from the elicitation.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// The elicitation response (accept with form values, decline, or cancel). - [JsonPropertyName("result")] - public UIElicitationResponse Result { get => field ??= new(); set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the pending UI request was resolved by this call. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIHandlePendingResult +public sealed class PermissionsModifyRulesResult { - /// True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. + /// Whether the operation succeeded. [JsonPropertyName("success")] public bool Success { get; set; } } -/// User response for a pending user-input request, with answer text and whether it was typed freeform. +/// Scope and add/remove instructions for modifying session- or location-scoped permission rules. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIUserInputResponse +internal sealed class PermissionsModifyRulesParams { - /// The user's answer text. - [JsonPropertyName("answer")] - public string Answer { get; set; } = string.Empty; + /// Rules to add to the scope. Applied before `remove`/`removeAll`. + [JsonPropertyName("add")] + public IList? Add { get; set; } - /// True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. - [JsonPropertyName("wasFreeform")] - public bool WasFreeform { get; set; } -} + /// Specific rules to remove from the scope. Ignored when `removeAll` is true. + [JsonPropertyName("remove")] + public IList? Remove { get; set; } -/// Request ID of a pending `user_input.requested` event and the user's response. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingUserInputRequest -{ - /// The unique request ID from the user_input.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. + [JsonPropertyName("removeAll")] + public bool? RemoveAll { get; set; } - /// User response for a pending user-input request, with answer text and whether it was typed freeform. - [JsonPropertyName("response")] - public UIUserInputResponse Response { get => field ??= new(); set; } + /// 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. + [JsonPropertyName("scope")] + public PermissionsModifyRulesScope Scope { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIHandlePendingSamplingResponse -{ -} - -/// Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingSamplingRequest +public sealed class PermissionsSetRequiredResult { - /// The unique request ID from the sampling.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. - [JsonPropertyName("response")] - public UIHandlePendingSamplingResponse? Response { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Request ID of a pending `auto_mode_switch.requested` event and the user's response. +/// Toggles whether permission prompts should be bridged into session events for this client. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingAutoModeSwitchRequest +internal sealed class PermissionsSetRequiredRequest { - /// The unique request ID from the auto_mode_switch.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). - [JsonPropertyName("response")] - public UIAutoModeSwitchResponse Response { get; set; } + /// Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). + [JsonPropertyName("required")] + public bool Required { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The user's selected action for an exhausted session limit. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UISessionLimitsExhaustedResponse +public sealed class PermissionsResetSessionApprovalsResult { - /// Action selected by the user. - [JsonPropertyName("action")] - public UISessionLimitsExhaustedResponseAction Action { get; set; } - - /// AI Credits to add to the current max when action is 'add'. - [JsonPropertyName("additionalAiCredits")] - public double? AdditionalAiCredits { get; set; } - - /// New absolute max AI Credits when action is 'set'. - [JsonPropertyName("maxAiCredits")] - public double? MaxAiCredits { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Request ID of a pending `session_limits_exhausted.requested` event and the user's selected limit action. +/// Clears session-scoped tool approvals and optionally clears location-scoped approvals and exact session-approved paths. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingSessionLimitsExhaustedRequest +internal sealed class PermissionsResetSessionApprovalsRequest { - /// The unique request ID from the session_limits_exhausted.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// The selected session-limit action. - [JsonPropertyName("response")] - public UISessionLimitsExhaustedResponse Response { get => field ??= new(); set; } + /// Whether location-scoped approvals and exact session-approved paths are cleared too. Defaults to `true`. + [JsonPropertyName("includeLocation")] + public bool? IncludeLocation { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIExitPlanModeResponse +public sealed class PermissionsNotifyPromptShownResult { - /// Whether the plan was approved. - [JsonPropertyName("approved")] - public bool Approved { get; set; } - - /// Whether subsequent edits should be auto-approved without confirmation. - [JsonPropertyName("autoApproveEdits")] - public bool? AutoApproveEdits { get; set; } - - /// When true, the agent is instructed to end its turn without starting implementation so the client can restore the session model and auto-submit a fresh implementation turn on it. Set only when a distinct plan configuration (a different model, reasoning effort, or context tier) actually ran the planning turn. - [JsonPropertyName("deferImplementation")] - public bool? DeferImplementation { get; set; } - - /// Feedback from the user when they declined the plan or requested changes. - [JsonPropertyName("feedback")] - public string? Feedback { get; set; } - - /// The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. - [JsonPropertyName("selectedAction")] - public UIExitPlanModeAction? SelectedAction { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Request ID of a pending `exit_plan_mode.requested` event and the user's response. +/// Notification payload describing the permission prompt that the client just rendered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingExitPlanModeRequest +internal sealed class PermissionPromptShownNotification { - /// The unique request ID from the exit_plan_mode.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. - [JsonPropertyName("response")] - public UIExitPlanModeResponse Response { get => field ??= new(); set; } + /// Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Register an in-process handler for `auto_mode_switch.requested` events. The 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). +/// Snapshot of the session's recursive directory grants, exact session-approved paths, and primary working directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIRegisterDirectAutoModeSwitchHandlerResult +public sealed class PermissionPathsList { - /// Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; + /// All directories currently allowed for tool access on this session. + [JsonPropertyName("directories")] + public IList Directories { get => field ??= []; set; } + + /// The primary working directory for this session. + [JsonPropertyName("primary")] + public string Primary { get; set; } = string.Empty; + + /// Exact paths approved for this session without recursively allowing their descendants. + [JsonPropertyName("sessionApprovedPaths")] + public IList? SessionApprovedPaths { get; set; } } -/// Identifies the target session. +/// No parameters; returns the session's recursive directory grants and exact session-approved paths. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionUiRegisterDirectAutoModeSwitchHandlerRequest +internal sealed class PermissionsPathsListRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the handle was active and the registration count was decremented. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIUnregisterDirectAutoModeSwitchHandlerResult +public sealed class PermissionsPathsAddResult { - /// True if the handle was active and decremented the counter; false if the handle was unknown. - [JsonPropertyName("unregistered")] - public bool Unregistered { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. +/// Directory path to add to the session's allowed directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIUnregisterDirectAutoModeSwitchHandlerRequest +internal sealed class PermissionPathsAddParams { - /// Handle previously returned by `registerDirectAutoModeSwitchHandler`. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; + /// Directory to add to the allow-list. The runtime resolves and validates the path before adding, then loads conventional `.github/skills/` and `.github/agents/` definitions under it when their subsystem gates are enabled. Adding the directory is therefore also a trust decision for configuration stored there. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] @@ -21253,216 +25726,165 @@ internal sealed class UIUnregisterDirectAutoModeSwitchHandlerRequest /// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureResult +public sealed class PermissionsPathsUpdatePrimaryResult { /// Whether the operation succeeded. [JsonPropertyName("success")] public bool Success { get; set; } } -/// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. +/// Directory path to set as the session's new primary working directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRuleSource +internal sealed class PermissionPathsUpdatePrimaryParams { - /// Name of the policy source. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Directory to set as the new primary working directory for the session's permission policy. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Type of the policy source. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Single content-exclusion rule supplied to `session.permissions.configure`, with paths, match conditions, and source. +/// Indicates whether the supplied path is within the session's allowed directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRule +public sealed class PermissionPathsAllowedCheckResult { - /// Conditions of which at least one must match. - [JsonPropertyName("ifAnyMatch")] - public IList? IfAnyMatch { get; set; } - - /// Conditions none of which may match. - [JsonPropertyName("ifNoneMatch")] - public IList? IfNoneMatch { get; set; } - - /// Path patterns covered by this rule. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } - - /// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. - [JsonPropertyName("source")] - public PermissionsConfigureAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } + /// Whether the path is within the session's allowed directories. + [JsonPropertyName("allowed")] + public bool Allowed { get; set; } } -/// Content-exclusion policy supplied to `session.permissions.configure`, with rules, last-updated data, and scope. +/// Path to evaluate against the session's allowed directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureAdditionalContentExclusionPolicy +internal sealed class PermissionPathsAllowedCheckParams { - /// Opaque policy update timestamp supplied by the host. - [JsonPropertyName("last_updated_at")] - public JsonElement LastUpdatedAt { get; set; } - - /// Content-exclusion rules to apply. - [JsonPropertyName("rules")] - public IList Rules { get => field ??= []; set; } + /// Path to check against the session's allowed directories. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. - [JsonPropertyName("scope")] - public PermissionsConfigureAdditionalContentExclusionPolicyScope Scope { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. +/// Indicates whether the supplied path is within the session's workspace directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsConfig +public sealed class PermissionPathsWorkspaceCheckResult { - /// Additional directories to allow tool access to (in addition to the session's working directory). Conventional `.github/skills/` and `.github/agents/` definitions under them also join the session catalogs when their subsystem gates are enabled, so supplying a directory is a trust decision for configuration stored there. When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). - [JsonPropertyName("additionalDirectories")] - public IList? AdditionalDirectories { get; set; } - - /// Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. - [JsonPropertyName("includeTempDirectory")] - public bool? IncludeTempDirectory { get; set; } + /// Whether the path is within the session workspace directory. + [JsonPropertyName("allowed")] + public bool Allowed { get; set; } +} - /// If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. - [JsonPropertyName("unrestricted")] - public bool? Unrestricted { get; set; } +/// Path to evaluate against the session's workspace (primary) directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionPathsWorkspaceCheckParams +{ + /// Path to check against the session workspace directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. - [JsonPropertyName("workspacePath")] - public string? WorkspacePath { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. +/// Resolved location-permissions key and type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionRulesSet +public sealed class PermissionLocationResolveResult { - /// Rules that auto-approve matching requests. - [JsonPropertyName("approved")] - public IList Approved { get => field ??= []; set; } + /// Location key used in the location-permissions store. + [JsonPropertyName("locationKey")] + public string LocationKey { get; set; } = string.Empty; - /// Rules that auto-deny matching requests. - [JsonPropertyName("denied")] - public IList Denied { get => field ??= []; set; } + /// Whether the location is a git repo or directory. + [JsonPropertyName("locationType")] + public PermissionLocationType LocationType { get; set; } } -/// 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. +/// Working directory to resolve into a location-permissions key. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionUrlsConfig +internal sealed class PermissionLocationResolveParams { - /// Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. - [JsonPropertyName("initialAllowed")] - public IList? InitialAllowed { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. - [JsonPropertyName("unrestricted")] - public bool? Unrestricted { get; set; } + /// Working directory whose permission location should be resolved. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Patch of permission policy fields to apply (omit a field to leave it unchanged). +/// Summary of persisted location permissions applied to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsConfigureParams +public sealed class PermissionLocationApplyResult { - /// 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. - [JsonPropertyName("additionalContentExclusionPolicies")] - public IList? AdditionalContentExclusionPolicies { get; set; } + /// Number of persisted allowed directories added to the live path manager. + [JsonPropertyName("appliedDirectoryCount")] + public long AppliedDirectoryCount { get; set; } - /// If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. - [JsonPropertyName("approveAllReadPermissionRequests")] - public bool? ApproveAllReadPermissionRequests { get; set; } + /// Number of location-scoped rules added to the live permission service. + [JsonPropertyName("appliedRuleCount")] + public long AppliedRuleCount { get; set; } - /// If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. - [JsonPropertyName("approveAllToolPermissionRequests")] - public bool? ApproveAllToolPermissionRequests { get; set; } + /// Location-scoped rules applied to the live permission service. + [JsonPropertyName("appliedRules")] + public IList AppliedRules { get => field ??= []; set; } - /// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. - [JsonPropertyName("paths")] - public PermissionPathsConfig? Paths { get; set; } + /// Whether a different location was applied since the previous apply call. + [JsonPropertyName("changed")] + public bool Changed { get; set; } - /// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. - [JsonPropertyName("rules")] - public PermissionRulesSet? Rules { get; set; } + /// Location key used in the location-permissions store. + [JsonPropertyName("locationKey")] + public string LocationKey { get; set; } = string.Empty; + + /// Whether the location is a git repo or directory. + [JsonPropertyName("locationType")] + public PermissionLocationType LocationType { get; set; } +} +/// Working directory to load persisted location permissions for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionLocationApplyParams +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// 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. - [JsonPropertyName("urls")] - public PermissionUrlsConfig? Urls { get; set; } + /// Working directory whose persisted location permissions should be applied. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Indicates whether the permission decision was applied; false when the request was already resolved. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionRequestResult +public sealed class PermissionsLocationsAddToolApprovalResult { - /// Whether the permission request was handled successfully. + /// Whether the operation succeeded. [JsonPropertyName("success")] public bool Success { get; set; } } -/// The client's response to the pending permission prompt. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionDecisionApproveOnce), "approve-once")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSession), "approve-for-session")] -[JsonDerivedType(typeof(PermissionDecisionApproveReadOnlyForSession), "approve-read-only-for-session")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocation), "approve-for-location")] -[JsonDerivedType(typeof(PermissionDecisionApprovePermanently), "approve-permanently")] -[JsonDerivedType(typeof(PermissionDecisionReject), "reject")] -[JsonDerivedType(typeof(PermissionDecisionUserNotAvailable), "user-not-available")] -[JsonDerivedType(typeof(PermissionDecisionApproved), "approved")] -[JsonDerivedType(typeof(PermissionDecisionApprovedForSession), "approved-for-session")] -[JsonDerivedType(typeof(PermissionDecisionApprovedForLocation), "approved-for-location")] -[JsonDerivedType(typeof(PermissionDecisionCancelled), "cancelled")] -[JsonDerivedType(typeof(PermissionDecisionDeniedByRules), "denied-by-rules")] -[JsonDerivedType(typeof(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser), "denied-no-approval-rule-and-could-not-request-from-user")] -[JsonDerivedType(typeof(PermissionDecisionDeniedInteractivelyByUser), "denied-interactively-by-user")] -[JsonDerivedType(typeof(PermissionDecisionDeniedByContentExclusionPolicy), "denied-by-content-exclusion-policy")] -[JsonDerivedType(typeof(PermissionDecisionDeniedByPermissionRequestHook), "denied-by-permission-request-hook")] -public partial class PermissionDecision -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} - - -/// Permission-decision request variant to approve only the current permission request. -/// The approve-once variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveOnce : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "approve-once"; - - /// True only when a host surfaced this request to a user who approved it. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approvedInteractively")] - public bool? ApprovedInteractively { get; set; } -} - -/// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). +/// Tool approval to persist and apply. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCommands), "commands")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalRead), "read")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWrite), "write")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcp), "mcp")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcpSampling), "mcp-sampling")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMemory), "memory")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCustomTool), "custom-tool")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionManagement), "extension-management")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWorkflow), "workflow")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess), "extension-permission-access")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionEnvAccess), "extension-env-access")] -public partial class PermissionDecisionApproveForSessionApproval +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCommands), "commands")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsRead), "read")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWrite), "write")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcp), "mcp")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcpSampling), "mcp-sampling")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMemory), "memory")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCustomTool), "custom-tool")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionManagement), "extension-management")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWorkflow), "workflow")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess), "extension-permission-access")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess), "extension-env-access")] +public partial class PermissionsLocationsAddToolApprovalDetails { /// The type discriminator. [JsonPropertyName("kind")] @@ -21470,10 +25892,10 @@ public partial class PermissionDecisionApproveForSessionApproval } -/// Session-scoped approval details for specific command identifiers. -/// The commands variant of . +/// Location-persisted tool approval details for specific command identifiers. +/// The commands variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalCommands : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsCommands : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -21484,30 +25906,30 @@ public partial class PermissionDecisionApproveForSessionApprovalCommands : Permi public required IList CommandIdentifiers { get; set; } } -/// Session-scoped approval details for read-only filesystem operations. -/// The read variant of . +/// Location-persisted tool approval details for read-only filesystem operations. +/// The read variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalRead : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsRead : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] public override string Kind => "read"; } -/// Session-scoped approval details for filesystem write operations. -/// The write variant of . +/// Location-persisted tool approval details for filesystem write operations. +/// The write variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalWrite : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsWrite : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] public override string Kind => "write"; } -/// Session-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. -/// The mcp variant of . +/// Location-persisted tool approval details for an MCP server tool, or all tools when `toolName` is null. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalMcp : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsMcp : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -21522,10 +25944,10 @@ public partial class PermissionDecisionApproveForSessionApprovalMcp : Permission public string? ToolName { get; set; } } -/// Session-scoped approval details for MCP sampling requests from a server. -/// The mcp-sampling variant of . +/// Location-persisted tool approval details for MCP sampling requests from a server. +/// The mcp-sampling variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalMcpSampling : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsMcpSampling : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -21536,20 +25958,20 @@ public partial class PermissionDecisionApproveForSessionApprovalMcpSampling : Pe public required string ServerName { get; set; } } -/// Session-scoped approval details for writes to long-term memory. -/// The memory variant of . +/// Location-persisted tool approval details for writes to long-term memory. +/// The memory variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalMemory : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsMemory : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] public override string Kind => "memory"; } -/// Session-scoped approval details for a custom tool, keyed by tool name. -/// The custom-tool variant of . +/// Location-persisted tool approval details for a custom tool, keyed by tool name. +/// The custom-tool variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalCustomTool : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsCustomTool : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -21560,10 +25982,10 @@ public partial class PermissionDecisionApproveForSessionApprovalCustomTool : Per public required string ToolName { get; set; } } -/// Session-scoped approval details for extension-management operations, optionally narrowed by operation. -/// The extension-management variant of . +/// Location-persisted tool approval details for extension-management operations, optionally narrowed by operation. +/// The extension-management variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalExtensionManagement : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsExtensionManagement : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -21575,5128 +25997,5379 @@ public partial class PermissionDecisionApproveForSessionApprovalExtensionManagem public string? Operation { get; set; } } -/// Session-scoped workflow approval, optionally narrowed by approval key. -/// The workflow variant of . +/// Location-persisted workflow approval, optionally narrowed by approval key. +/// The workflow variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalWorkflow : PermissionDecisionApproveForSessionApproval +public partial class PermissionsLocationsAddToolApprovalDetailsWorkflow : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] public override string Kind => "workflow"; - /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approvalKey")] - public string? ApprovalKey { get; set; } + /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("approvalKey")] + public string? ApprovalKey { get; set; } +} + +/// Location-persisted tool approval details for an extension's permission-gated capability access, keyed by extension name. +/// The extension-permission-access variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess : PermissionsLocationsAddToolApprovalDetails +{ + /// + [JsonIgnore] + public override string Kind => "extension-permission-access"; + + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } +} + +/// Location-persisted tool approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. +/// The extension-env-access variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess : PermissionsLocationsAddToolApprovalDetails +{ + /// + [JsonIgnore] + public override string Kind => "extension-env-access"; + + /// Names of the sensitive environment variables this approval covers. Values are never persisted. + [JsonPropertyName("environmentVariables")] + public required IList EnvironmentVariables { get; set; } + + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } +} + +/// Location-scoped tool approval to persist. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionLocationAddToolApprovalParams +{ + /// Tool approval to persist and apply. + [JsonPropertyName("approval")] + public PermissionsLocationsAddToolApprovalDetails Approval { get => field ??= new(); set; } + + /// Location key (git root or cwd) to persist the approval to. + [JsonPropertyName("locationKey")] + public string LocationKey { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Folder path to check for trust. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FolderTrustCheckParams +{ + /// Folder path to check. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the operation succeeded. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionsFolderTrustAddTrustedResult +{ + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// Folder path to add to trusted folders. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FolderTrustAddParams +{ + /// Folder path to mark as trusted. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the operation succeeded. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionsUrlsSetUnrestrictedModeResult +{ + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// Whether the URL-permission policy should run in unrestricted mode. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionUrlsSetUnrestrictedModeParams +{ + /// Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The repository the remote session targets. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MetadataSnapshotRemoteMetadataRepository +{ + /// The branch the remote session is operating on. + [JsonPropertyName("branch")] + public string Branch { get; set; } = string.Empty; + + /// The GitHub repository name (without owner). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// The GitHub owner (user or organization) of the target repository. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; +} + +/// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MetadataSnapshotRemoteMetadata +{ + /// The pull request number the remote session is associated with, if any. + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } + + /// The repository the remote session targets. + [JsonPropertyName("repository")] + public MetadataSnapshotRemoteMetadataRepository Repository { get => field ??= new(); set; } + + /// The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } + + /// Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. + [JsonPropertyName("taskType")] + public MetadataSnapshotRemoteMetadataTaskType? TaskType { get; set; } +} + +/// Public-facing projection of workspace metadata for SDK / TUI consumers. +public sealed class SessionMetadataSnapshotWorkspace +{ + /// Branch checked out at session start, if any. + [JsonPropertyName("branch")] + public string? Branch { get; set; } + + /// ISO 8601 timestamp when the workspace was created. + [JsonPropertyName("created_at")] + public DateTimeOffset? CreatedAt { get; set; } + + /// Current working directory at session start. + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } + + /// Resolved git root for cwd, if any. + [JsonPropertyName("git_root")] + public string? GitRoot { get; set; } + + /// Repository host type, if known. + [JsonPropertyName("host_type")] + public WorkspaceSummaryHostType? HostType { get; set; } + + /// Workspace identifier (1:1 with sessionId). + [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("id")] + public string Id { get; set; } = string.Empty; + + /// Display name for the session, if set. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Repository identifier in 'owner/repo' or 'org/project/repo' format, if any. + [JsonPropertyName("repository")] + public string? Repository { get; set; } + + /// ISO 8601 timestamp when the workspace was last updated. + [JsonPropertyName("updated_at")] + public DateTimeOffset? UpdatedAt { get; set; } + + /// Whether the display name was explicitly set by the user. + [JsonPropertyName("user_named")] + public bool? UserNamed { get; set; } } -/// Session-scoped approval details for an extension's permission-gated capability access, keyed by extension name. -/// The extension-permission-access variant of . +/// Point-in-time snapshot of slow-changing session identifier and state fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess : PermissionDecisionApproveForSessionApproval +public sealed class SessionMetadataSnapshot { - /// - [JsonIgnore] - public override string Kind => "extension-permission-access"; + /// True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. + [JsonPropertyName("alreadyInUse")] + public bool AlreadyInUse { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } -} + /// Runtime client name associated with the session (telemetry identifier). + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } -/// Session-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. -/// The extension-env-access variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalExtensionEnvAccess : PermissionDecisionApproveForSessionApproval -{ - /// - [JsonIgnore] - public override string Kind => "extension-env-access"; + /// The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot'). + [JsonPropertyName("currentMode")] + public MetadataSnapshotCurrentMode CurrentMode { get; set; } - /// Names of the sensitive environment variables this approval covers. Values are never persisted. - [JsonPropertyName("environmentVariables")] - public required IList EnvironmentVariables { get; set; } + /// Live indexed-search state for this session activation. Omitted by runtimes that do not expose indexed-search status; absence does not indicate enablement. + [JsonPropertyName("indexedSearch")] + public IndexedSearchState? IndexedSearch { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } -} + /// User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. + [JsonPropertyName("initialName")] + public string? InitialName { get; set; } -/// Permission-decision request variant to approve for the rest of the session, with optional tool approval or URL domain. -/// The approve-for-session variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSession : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "approve-for-session"; + /// Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process). + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } - /// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approval")] - public PermissionDecisionApproveForSessionApproval? Approval { get; set; } + /// ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. + [JsonPropertyName("modifiedTime")] + public DateTimeOffset ModifiedTime { get; set; } - /// URL domain to approve for the rest of the session (URL prompts only). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("domain")] - public string? Domain { get; set; } -} + /// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. + [JsonPropertyName("remoteMetadata")] + public MetadataSnapshotRemoteMetadata? RemoteMetadata { get; set; } -/// Approve file-tool read access to specific directories for this logical session, including continuation or resume. -/// The approve-read-only-for-session variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveReadOnlyForSession : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "approve-read-only-for-session"; + /// Currently selected model identifier, if any. + [JsonPropertyName("selectedModel")] + public string? SelectedModel { get; set; } - /// Canonical directories covered by the read-only grant. - [JsonPropertyName("directories")] - public required IList Directories { get; set; } -} + /// The unique identifier of the session. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; -/// Approval to persist for this location. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCommands), "commands")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalRead), "read")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWrite), "write")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcp), "mcp")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcpSampling), "mcp-sampling")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMemory), "memory")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCustomTool), "custom-tool")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionManagement), "extension-management")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWorkflow), "workflow")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess), "extension-permission-access")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionEnvAccess), "extension-env-access")] -public partial class PermissionDecisionApproveForLocationApproval -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Current session limits, or null when no limits are active. + [JsonPropertyName("sessionLimits")] + public SessionLimitsConfig? SessionLimits { get; set; } + /// ISO 8601 timestamp of when the session started. + [JsonPropertyName("startTime")] + public DateTimeOffset StartTime { get; set; } -/// Location-scoped approval details for specific command identifiers. -/// The commands variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalCommands : PermissionDecisionApproveForLocationApproval -{ - /// - [JsonIgnore] - public override string Kind => "commands"; + /// Short human-readable summary of the session, if known. Omitted when no summary has been generated. + [JsonPropertyName("summary")] + public string? Summary { get; set; } - /// Command identifiers covered by this approval. - [JsonPropertyName("commandIdentifiers")] - public required IList CommandIdentifiers { get; set; } + /// Absolute path to the session's current working directory. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; + + /// Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). + [JsonPropertyName("workspace")] + public SessionMetadataSnapshotWorkspace? Workspace { get; set; } + + /// Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace. + [JsonPropertyName("workspacePath")] + public string? WorkspacePath { get; set; } } -/// Location-scoped approval details for read-only filesystem operations. -/// The read variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalRead : PermissionDecisionApproveForLocationApproval +internal sealed class SessionMetadataSnapshotRequest { - /// - [JsonIgnore] - public override string Kind => "read"; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-scoped approval details for filesystem write operations. -/// The write variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalWrite : PermissionDecisionApproveForLocationApproval +internal sealed class SessionMetadataGetClientMetadataRequest { - /// - [JsonIgnore] - public override string Kind => "write"; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. -/// The mcp variant of . +/// Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalMcp : PermissionDecisionApproveForLocationApproval +internal sealed class MetadataUpdateClientMetadataRequest { - /// - [JsonIgnore] - public override string Kind => "mcp"; + /// Remove every existing client metadata entry before applying remove and set. Defaults to false. + [JsonPropertyName("clear")] + public bool? Clear { get; set; } - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Case-sensitive keys to remove. Missing keys are ignored. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. + [JsonPropertyName("remove")] + public IList? Remove { get; set; } - /// MCP tool name, or null to cover every tool on the server. - [JsonPropertyName("toolName")] - public string? ToolName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// String entries to add or replace. Set wins when a key also appears in remove. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Each value may contain at most 16 KiB of UTF-8 data. + [JsonPropertyName("set")] + public IDictionary? Set { get; set; } } -/// Location-scoped approval details for MCP sampling requests from a server. -/// The mcp-sampling variant of . +/// Indicates whether the local session is currently processing a turn or background continuation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalMcpSampling : PermissionDecisionApproveForLocationApproval +public sealed class MetadataIsProcessingResult { - /// - [JsonIgnore] - public override string Kind => "mcp-sampling"; - - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. + [JsonPropertyName("processing")] + public bool Processing { get; set; } } -/// Location-scoped approval details for writes to long-term memory. -/// The memory variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalMemory : PermissionDecisionApproveForLocationApproval +internal sealed class SessionMetadataIsProcessingRequest { - /// - [JsonIgnore] - public override string Kind => "memory"; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-scoped approval details for a custom tool, keyed by tool name. -/// The custom-tool variant of . +/// Current activity flags for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalCustomTool : PermissionDecisionApproveForLocationApproval +public sealed class SessionActivity { - /// - [JsonIgnore] - public override string Kind => "custom-tool"; + /// Whether an in-flight operation can currently be aborted. + [JsonPropertyName("abortable")] + public bool Abortable { get; set; } - /// Custom tool name. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } + /// Whether the session currently has active work, including running turns or tasks. + [JsonPropertyName("hasActiveWork")] + public bool HasActiveWork { get; set; } } -/// Location-scoped approval details for extension-management operations, optionally narrowed by operation. -/// The extension-management variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalExtensionManagement : PermissionDecisionApproveForLocationApproval +internal sealed class SessionMetadataActivityRequest { - /// - [JsonIgnore] - public override string Kind => "extension-management"; - - /// Optional operation identifier; when omitted, the approval covers all extension management operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operation")] - public string? Operation { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-scoped workflow approval, optionally narrowed by approval key. -/// The workflow variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalWorkflow : PermissionDecisionApproveForLocationApproval +/// Token-usage breakdown for the session's current context window. +public sealed class MetadataContextInfoResultContextInfo { - /// - [JsonIgnore] - public override string Kind => "workflow"; + /// Output reservation overlapping the displayed prompt allowance plus tokens after the effective input budget's buffer-exhaustion blocking threshold (default 95%). + [JsonPropertyName("bufferTokens")] + public long BufferTokens { get; set; } - /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approvalKey")] - public string? ApprovalKey { get; set; } -} + /// Token count at which background compaction starts (configurable percentage of promptTokenLimit). + [JsonPropertyName("compactionThreshold")] + public long CompactionThreshold { get; set; } -/// Location-scoped approval details for an extension's permission-gated capability access, keyed by extension name. -/// The extension-permission-access variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess : PermissionDecisionApproveForLocationApproval -{ - /// - [JsonIgnore] - public override string Kind => "extension-permission-access"; + /// Tokens consumed by user/assistant/tool messages. + [JsonPropertyName("conversationTokens")] + public long ConversationTokens { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } -} + /// Provider-owned model display label, or the Auto routing label. Presentation only; modelName remains the tokenization identity. + [JsonPropertyName("displayModelName")] + public string? DisplayModelName { get; set; } -/// Location-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. -/// The extension-env-access variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalExtensionEnvAccess : PermissionDecisionApproveForLocationApproval -{ - /// - [JsonIgnore] - public override string Kind => "extension-env-access"; + /// Advertised prompt allowance for the selected context tier, without adding output tokens. The denominator for context-usage displays. + [JsonPropertyName("limit")] + public long Limit { get; set; } - /// Names of the sensitive environment variables this approval covers. Values are never persisted. - [JsonPropertyName("environmentVariables")] - public required IList EnvironmentVariables { get; set; } + /// Tokens consumed by MCP tool definitions (subset of toolDefinitionsTokens, excludes deferred tools). + [JsonPropertyName("mcpToolsTokens")] + public long McpToolsTokens { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } -} + /// The model used for token counting. + [JsonPropertyName("modelName")] + public string ModelName { get; set; } = string.Empty; -/// Permission-decision request variant to approve and persist a permission for a project location, with approval details and location key. -/// The approve-for-location variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocation : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "approve-for-location"; + /// Effective input budget: the selected tier's prompt allowance bounded by the combined context ceiling minus the requested output allowance. Uses DEFAULT_TOKEN_LIMIT when limits are unspecified. + [JsonPropertyName("promptTokenLimit")] + public long PromptTokenLimit { get; set; } - /// Approval to persist for this location. - [JsonPropertyName("approval")] - public required PermissionDecisionApproveForLocationApproval Approval { get; set; } + /// Provider whose catalog supplies this context window. Omitted when provider identity is unavailable. + [JsonPropertyName("provider")] + public ModelProviderRef? Provider { get; set; } - /// Location key (git root or cwd) to persist the approval to. - [JsonPropertyName("locationKey")] - public required string LocationKey { get; set; } + /// Tokens consumed by the system prompt. + [JsonPropertyName("systemTokens")] + public long SystemTokens { get; set; } + + /// Tokens consumed by tool definitions sent to the model (excludes deferred tools). + [JsonPropertyName("toolDefinitionsTokens")] + public long ToolDefinitionsTokens { get; set; } + + /// Sum of system, conversation and tool-definition tokens. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Permission-decision request variant to permanently approve a URL domain across sessions. -/// The approve-permanently variant of . +/// Token breakdown for the session's current context window, or null if uninitialized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApprovePermanently : PermissionDecision +public sealed class MetadataContextInfoResult { - /// - [JsonIgnore] - public override string Kind => "approve-permanently"; - - /// URL domain to approve permanently. - [JsonPropertyName("domain")] - public required string Domain { get; set; } + /// Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + [JsonPropertyName("contextInfo")] + public MetadataContextInfoResultContextInfo? ContextInfo { get; set; } } -/// Permission-decision request variant to reject a pending permission request, with optional feedback. -/// The reject variant of . +/// Model identifier and token limits used to compute the context-info breakdown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionReject : PermissionDecision +internal sealed class MetadataContextInfoRequest { - /// - [JsonIgnore] - public override string Kind => "reject"; + /// Requested output allowance to reserve against the combined context ceiling. Pass 0 to resolve the session's request cap, falling back to the model's advertised output limit. + [JsonPropertyName("outputTokenLimit")] + public long OutputTokenLimit { get; set; } - /// Optional feedback explaining the rejection. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("feedback")] - public string? Feedback { get; set; } + /// Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from the session. + [JsonPropertyName("promptTokenLimit")] + public long PromptTokenLimit { get; set; } + + /// Provider owning selectedModel. Omit to use the current provider for the current model, or deterministic legacy lookup for a different model. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. + [JsonPropertyName("selectedModel")] + public string? SelectedModel { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Permission-decision variant indicating no user was available to confirm the request. -/// The user-not-available variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionUserNotAvailable : PermissionDecision +/// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. +public sealed class MetadataContextAttributionResultContextAttributionCategories { - /// - [JsonIgnore] - public override string Kind => "user-not-available"; + /// Overlapping output reservation plus post-blocking-threshold buffer. + [JsonPropertyName("buffer")] + public long Buffer { get; set; } + + /// Custom-instructions tokens (0 when none are configured). + [JsonPropertyName("customInstructions")] + public long CustomInstructions { get; set; } + + /// Remaining unused window capacity (clamped at 0). + [JsonPropertyName("freeSpace")] + public long FreeSpace { get; set; } + + /// MCP tool-definition tokens. + [JsonPropertyName("mcpTools")] + public long McpTools { get; set; } + + /// Conversation (user/assistant/tool) message tokens. + [JsonPropertyName("messages")] + public long Messages { get; set; } + + /// System prompt tokens, excluding custom instructions. + [JsonPropertyName("systemPrompt")] + public long SystemPrompt { get; set; } + + /// Non-MCP tool-definition tokens. + [JsonPropertyName("systemTools")] + public long SystemTools { get; set; } } -/// Permission-decision variant indicating the request was approved. -/// The approved variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproved : PermissionDecision +/// Successful compaction history for the session. +public sealed class MetadataContextAttributionResultContextAttributionCompactions { - /// - [JsonIgnore] - public override string Kind => "approved"; + /// Number of successful compactions in this session. + [JsonPropertyName("count")] + public long Count { get; set; } } -/// Permission-decision variant indicating approval was remembered for the session, with approval details. -/// The approved-for-session variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApprovedForSession : PermissionDecision +/// RPC data type for MetadataContextAttributionResultContextAttributionEntry operations. +public sealed class MetadataContextAttributionResultContextAttributionEntry { - /// - [JsonIgnore] - public override string Kind => "approved-for-session"; + /// Supplementary per-entry metadata (e.g. `messageCount`, `role`, `evictable`, `pluginSource`). Values are stringified; parse as needed and ignore unrecognized keys. + [JsonPropertyName("attributes")] + public IDictionary? Attributes { get; set; } - /// The approval to add as a session-scoped rule. - [JsonPropertyName("approval")] - public required UserToolSessionApproval Approval { get; set; } -} + /// Identifier for this entry, formed by joining its `kind` and source name (e.g. `tool:bash`, `skill:tmux`, `toolDefinition:bash`); unique within the snapshot. Use it to match the same entry across snapshots, to correlate with other APIs (skill/agent/MCP registries), and as the `parentId` target for nesting. Distinct from the human-facing `label`. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// Permission-decision variant indicating approval was persisted for a project location, with approval details and location key. -/// The approved-for-location variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApprovedForLocation : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "approved-for-location"; + /// Source category for this entry. Not a closed set — tolerate unknown values. Known values today: `skill`, `subagent`, `mcpServer`, `tool`, `system`, `toolDefinition`, `plugin`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; - /// The approval to persist for this location. - [JsonPropertyName("approval")] - public required UserToolSessionApproval Approval { get; set; } + /// Human-readable display label, e.g. `bash` or `skill: tmux`. Presentation-only; may be localized/reformatted without notice — do not key off it. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; - /// The location key (git root or cwd) to persist the approval to. - [JsonPropertyName("locationKey")] - public required string LocationKey { get; set; } + /// Optional `id` of the parent entry: e.g. a `plugin` entry parenting its `skill`/`mcpServer` entries, or the `system` entry parenting `toolDefinition` entries. Omitted for top-level entries. + [JsonPropertyName("parentId")] + public string? ParentId { get; set; } + + /// Token count currently in context attributable to this entry. + [JsonPropertyName("tokens")] + public long Tokens { get; set; } } -/// Permission-decision variant indicating the request was cancelled before use, with an optional reason. -/// The cancelled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionCancelled : PermissionDecision +/// Per-source token attribution snapshot for the current context window. The heaviest individual messages are available separately via `metadata.getContextHeaviestMessages`. +public sealed class MetadataContextAttributionResultContextAttribution { - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// Output reservation overlapping the displayed prompt allowance plus the tokens past the effective input budget's buffer-exhaustion blocking threshold. Mirrors `SessionContextInfo.bufferTokens`. + [JsonPropertyName("bufferTokens")] + public long BufferTokens { get; set; } - /// Optional explanation of why the request was cancelled. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reason")] - public string? Reason { get; set; } -} + /// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. + [JsonPropertyName("categories")] + public MetadataContextAttributionResultContextAttributionCategories Categories { get => field ??= new(); set; } + + /// Successful compaction history for the session. + [JsonPropertyName("compactions")] + public MetadataContextAttributionResultContextAttributionCompactions Compactions { get => field ??= new(); set; } + + /// Token count at which background compaction starts. Mirrors `SessionContextInfo.compactionThreshold`. + [JsonPropertyName("compactionThreshold")] + public long CompactionThreshold { get; set; } + + /// Flat list of per-source attribution entries. Group by `kind` and render unrecognized kinds generically. Nesting and rollups are expressed via `parentId`. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } + + /// Advertised prompt allowance for the selected context tier: the denominator for context-usage displays and capacity for `categories.freeSpace` and `categories.buffer`. Mirrors `SessionContextInfo.limit`. + [JsonPropertyName("limit")] + public long Limit { get; set; } + + /// The concrete model id the entire breakdown was tokenized against (feeds the per-model token multiplier). Under `Auto` (Free/Student) this is the resolved model, not the literal `auto` sentinel, so totals are not undercounted. A single-model approximation of a potentially multi-model Auto session. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; -/// Permission-decision variant indicating explicit denial by permission rules, with the matching rules. -/// The denied-by-rules variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedByRules : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "denied-by-rules"; + /// How `modelId` was chosen. Not a closed set — tolerate unknown values. Known values today: `autoResolved` (the model Auto resolved to), `selected` (the user's explicitly selected model), `default` (a fallback before any model is known). + [JsonPropertyName("modelSource")] + public string ModelSource { get; set; } = string.Empty; - /// Rules that denied the request. - [JsonPropertyName("rules")] - public required IList Rules { get; set; } + /// Effective input budget after reserving requested output against the combined context ceiling. Mirrors `SessionContextInfo.promptTokenLimit`. + [JsonPropertyName("promptTokenLimit")] + public long PromptTokenLimit { get; set; } + + /// Total token count of the current context window the entries are measured against (system message + conversation messages + tool definitions — the same total reported by /context). Divide an entry's `tokens` by this to derive its share. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Permission-decision variant indicating no approval rule matched and user confirmation was unavailable. -/// The denied-no-approval-rule-and-could-not-request-from-user variant of . +/// Per-source attribution breakdown for the session's current context window, or null if uninitialized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser : PermissionDecision +public sealed class MetadataContextAttributionResult { - /// - [JsonIgnore] - public override string Kind => "denied-no-approval-rule-and-could-not-request-from-user"; + /// Per-source context-window attribution, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + [JsonPropertyName("contextAttribution")] + public MetadataContextAttributionResultContextAttribution? ContextAttribution { get; set; } } -/// Permission-decision variant indicating the user denied an interactive prompt, with optional feedback and force-reject flag. -/// The denied-interactively-by-user variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedInteractivelyByUser : PermissionDecision +internal sealed class SessionMetadataGetContextAttributionRequest { - /// - [JsonIgnore] - public override string Kind => "denied-interactively-by-user"; - - /// Optional feedback from the user explaining the denial. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("feedback")] - public string? Feedback { get; set; } - - /// Whether to force-reject the current agent turn. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("forceReject")] - public bool? ForceReject { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Permission-decision variant indicating denial by content-exclusion policy, with path and message. -/// The denied-by-content-exclusion-policy variant of . +/// A single large message currently in context. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedByContentExclusionPolicy : PermissionDecision +public sealed class ContextHeaviestMessage { - /// - [JsonIgnore] - public override string Kind => "denied-by-content-exclusion-policy"; + /// Stable identifier for this message within the snapshot. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Human-readable explanation of why the path was excluded. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Human-readable source label, e.g. `tool: bash` or `skill: tmux`. Presentation-only. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; - /// File path that triggered the exclusion. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Role of the chat message (`user`, `assistant`, or `tool`). + [JsonPropertyName("role")] + public string Role { get; set; } = string.Empty; + + /// Token count currently in context for this individual message. + [JsonPropertyName("tokens")] + public long Tokens { get; set; } } -/// Permission-decision variant indicating denial by a permission request hook, with optional message and interrupt flag. -/// The denied-by-permission-request-hook variant of . +/// The heaviest individual messages in the session's context window, most-expensive first. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedByPermissionRequestHook : PermissionDecision +public sealed class MetadataContextHeaviestMessagesResult { - /// - [JsonIgnore] - public override string Kind => "denied-by-permission-request-hook"; - - /// Whether to interrupt the current agent turn. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("interrupt")] - public bool? Interrupt { get; set; } + /// Heaviest messages, most-expensive first. + [JsonPropertyName("messages")] + public IList Messages { get => field ??= []; set; } - /// Optional message from the hook explaining the denial. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Total token count of the current context window, so callers can compute each message's share without a second call. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Pending permission request ID and the decision to apply (approve/reject and scope). +/// Parameters for the heaviest-messages query. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionDecisionRequest +internal sealed class MetadataContextHeaviestMessagesRequest { - /// Optional informational context describing how and where this response was made. Omit it to preserve legacy behavior without attributing an origin. - [JsonPropertyName("decisionContext")] - public PermissionDecisionContext? DecisionContext { get; set; } - - /// Request ID of the pending permission request. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// The client's response to the pending permission prompt. - [JsonPropertyName("result")] - public PermissionDecision Result { get => field ??= new(); set; } + /// Maximum number of messages to return, most-expensive first. Omit for the server default. + [JsonPropertyName("limit")] + public long? Limit { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Pending permission prompt reconstructed from event history, with request ID and user-facing prompt details. +/// Notify the session that its working directory context has changed. Emits a `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). For a local session, a report whose `cwd` diverges from the session's current working directory is ignored (the call still succeeds but records nothing and emits no event); move a local session's working directory via `metadata.setWorkingDirectory` instead. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PendingPermissionRequest +public sealed class MetadataRecordContextChangeResult { - /// Permission-recovery episode that authorized this request to surface for interactive attention. - [JsonPropertyName("recoveryEpisodeId")] - public string? RecoveryEpisodeId { get; set; } +} - /// The user-facing permission prompt details (commands, write, read, mcp, url, memory, custom-tool, path, hook). - [JsonPropertyName("request")] - public PermissionPromptRequest Request { get; set; } = null!; +/// Updated working-directory/git context to record on the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class MetadataRecordContextChangeRequest +{ + /// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. + [JsonPropertyName("context")] + public SessionWorkingDirectoryContext Context { get => field ??= new(); set; } - /// Unique identifier for the pending permission request. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// List of pending permission requests reconstructed from event history. +/// Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for any related side-effects (file index, etc.); it does NOT change the process working directory (a session's cwd is per-session, not process-global). For local sessions the runtime validates the target first (an absolute path that exists on disk) and re-bases the permission primary directory; a rejected validation fails the call before anything is mutated, persisted, or emitted. Location-scoped permission rules are then re-keyed to the new directory (best-effort). Remote sessions only record the path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PendingPermissionRequestList +public sealed class MetadataSetWorkingDirectoryResult { - /// Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } + /// Working directory after the update. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// No parameters; returns currently-pending permission requests for the session. +/// Absolute path to set as the session's new working directory. For local sessions the path must be absolute and exist on disk: it is validated before any session state changes, and a failing validation rejects the call with nothing mutated, persisted, or emitted. Remote sessions record the path as-is. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsPendingRequestsRequest +internal sealed class MetadataSetWorkingDirectoryRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// Re-tokenize the session's existing messages against `modelId` and return the 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsSetApproveAllResult +public sealed class MetadataRecomputeContextTokensResult { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). + [JsonPropertyName("messagesTokenCount")] + public long MessagesTokenCount { get; set; } + + /// Tokens contributed by system/developer prompt snapshots. + [JsonPropertyName("systemTokenCount")] + public long SystemTokenCount { get; set; } + + /// Sum of tokens across chat-context and system-context messages currently held by the session. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Allow-all toggle for tool permission requests, with an optional telemetry source. +/// Model identifier to use when re-tokenizing the session's existing messages. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsSetApproveAllRequest +internal sealed class MetadataRecomputeContextTokensRequest { - /// Whether to auto-approve all tool permission requests. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; /// 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 PermissionsSetApproveAllSource? Source { get; set; } } -/// Indicates whether the requested permission mode was applied and reports the authoritative post-mutation mode. +/// Availability of built-in job tools surfaced to boundary consumers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsSetModeResult +public sealed class SessionSettingsBuiltInToolAvailabilitySnapshot { - /// Authoritative permission mode after the mutation. - [JsonPropertyName("mode")] - public PermissionMode Mode { get; set; } + /// Whether the create-pull-request tool is available. + [JsonPropertyName("createPullRequest")] + public bool? CreatePullRequest { get; set; } - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the report-progress tool is available. + [JsonPropertyName("reportProgress")] + public bool? ReportProgress { get; set; } } -/// Permission mode to apply for the session. +/// Redacted job settings for a session. The job nonce is excluded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsSetModeRequest +public sealed class SessionSettingsJobSnapshot { - /// Optional judge model id for assisted mode. When omitted, the session resolves the provider default: `gpt-5.5` for CAPI sessions and the active session model for BYOK sessions. - [JsonPropertyName("assistedApprovalModel")] - public string? AssistedApprovalModel { get; set; } - - /// Permission mode to apply. - [JsonPropertyName("mode")] - public PermissionMode Mode { get; set; } + /// Availability of job-specific built-in tools. + [JsonPropertyName("builtInToolAvailability")] + public SessionSettingsBuiltInToolAvailabilitySnapshot? BuiltInToolAvailability { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// GitHub Actions event type for the job. + [JsonPropertyName("eventType")] + public string? EventType { get; set; } - /// Optional source for permission-mode telemetry. `organization_targeting` is reserved for startup selection after the authenticated account matches an organization targeting policy; SDK callers default to `rpc` and cannot claim targeting provenance. - [JsonPropertyName("source")] - public PermissionModeSource? Source { get; set; } + /// Whether this is the workflow's trigger job. + [JsonPropertyName("isTriggerJob")] + public bool? IsTriggerJob { get; set; } } -/// Current permission mode. +/// Redacted model routing settings for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsGetModeResult +public sealed class SessionSettingsModelSnapshot { - /// Current permission mode. - [JsonPropertyName("mode")] - public PermissionMode Mode { get; set; } + /// Agent service callback URL for job and progress updates. + [JsonPropertyName("callbackUrl")] + public string? CallbackUrl { get; set; } + + /// Default reasoning effort for the selected model. + [JsonPropertyName("defaultReasoningEffort")] + public string? DefaultReasoningEffort { get; set; } + + /// Agent job identifier for the session. + [JsonPropertyName("instanceId")] + public string? InstanceId { get; set; } + + /// Selected model identifier. + [JsonPropertyName("model")] + public string? Model { get; set; } } -/// No parameters. +/// Online-evaluation settings safe to expose across the SDK boundary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsGetModeRequest +public sealed class SessionSettingsOnlineEvaluationSnapshot { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether online evaluation is disabled. + [JsonPropertyName("disableOnlineEvaluation")] + public bool? DisableOnlineEvaluation { get; set; } + + /// Whether online-evaluation output-file generation is enabled. + [JsonPropertyName("enableOnlineEvaluationOutputFile")] + public bool? EnableOnlineEvaluationOutputFile { get; set; } } -/// Indicates whether the operation succeeded. +/// Redacted repository and GitHub host settings for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsModifyRulesResult +public sealed class SessionSettingsRepoSnapshot { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Checked-out repository branch. + [JsonPropertyName("branch")] + public string? Branch { get; set; } + + /// Checked-out commit SHA. + [JsonPropertyName("commit")] + public string? Commit { get; set; } + + /// GitHub server host name. + [JsonPropertyName("host")] + public string? Host { get; set; } + + /// Protocol used to access the GitHub host. + [JsonPropertyName("hostProtocol")] + public string? HostProtocol { get; set; } + + /// GitHub repository database ID. + [JsonPropertyName("id")] + public double? Id { get; set; } + + /// Repository name. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// GitHub repository owner database ID. + [JsonPropertyName("ownerId")] + public double? OwnerId { get; set; } + + /// Repository owner login. + [JsonPropertyName("ownerName")] + public string? OwnerName { get; set; } + + /// Number of commits in the pull request. + [JsonPropertyName("prCommitCount")] + public double? PrCommitCount { get; set; } + + /// Whether the repository is writable. + [JsonPropertyName("readWrite")] + public bool? ReadWrite { get; set; } + + /// GitHub secret-scanning service URL. + [JsonPropertyName("secretScanningUrl")] + public string? SecretScanningUrl { get; set; } + + /// GitHub server base URL. + [JsonPropertyName("serverUrl")] + public string? ServerUrl { get; set; } } -/// Scope and add/remove instructions for modifying session- or location-scoped permission rules. +/// Redacted validation and memory-tool settings for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsModifyRulesParams +public sealed class SessionSettingsValidationSnapshot { - /// Rules to add to the scope. Applied before `remove`/`removeAll`. - [JsonPropertyName("add")] - public IList? Add { get; set; } + /// Whether advisory validation is enabled. + [JsonPropertyName("advisoryEnabled")] + public bool? AdvisoryEnabled { get; set; } - /// Specific rules to remove from the scope. Ignored when `removeAll` is true. - [JsonPropertyName("remove")] - public IList? Remove { get; set; } + /// Whether CodeQL validation is enabled. + [JsonPropertyName("codeqlEnabled")] + public bool? CodeqlEnabled { get; set; } - /// When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. - [JsonPropertyName("removeAll")] - public bool? RemoveAll { get; set; } + /// Whether code-review validation is enabled. + [JsonPropertyName("codeReviewEnabled")] + public bool? CodeReviewEnabled { get; set; } - /// 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. - [JsonPropertyName("scope")] - public PermissionsModifyRulesScope Scope { get; set; } + /// Model used for code-review validation. + [JsonPropertyName("codeReviewModel")] + public string? CodeReviewModel { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Dependabot validation timeout budget in seconds. + [JsonPropertyName("dependabotTimeout")] + public double? DependabotTimeout { get; set; } + + /// Whether the memory-store tool is enabled. + [JsonPropertyName("memoryStoreEnabled")] + public bool? MemoryStoreEnabled { get; set; } + + /// Whether the memory-vote tool is enabled. + [JsonPropertyName("memoryVoteEnabled")] + public bool? MemoryVoteEnabled { get; set; } + + /// Whether secret-scanning validation is enabled. + [JsonPropertyName("secretScanningEnabled")] + public bool? SecretScanningEnabled { get; set; } + + /// General validation timeout budget in seconds. + [JsonPropertyName("timeout")] + public double? Timeout { get; set; } } -/// Indicates whether the operation succeeded. +/// Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsSetRequiredResult +internal sealed class SessionSettingsSnapshot { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Name of the SDK client that created the session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Redacted job settings. + [JsonPropertyName("job")] + public SessionSettingsJobSnapshot Job { get => field ??= new(); set; } + + /// Redacted model routing settings. + [JsonPropertyName("model")] + public SessionSettingsModelSnapshot Model { get => field ??= new(); set; } + + /// Online-evaluation settings safe for SDK consumers. + [JsonPropertyName("onlineEvaluation")] + public SessionSettingsOnlineEvaluationSnapshot OnlineEvaluation { get => field ??= new(); set; } + + /// Redacted repository and host settings. + [JsonPropertyName("repo")] + public SessionSettingsRepoSnapshot Repo { get => field ??= new(); set; } + + /// Session start time as Unix epoch milliseconds. + [JsonPropertyName("startTimeMs")] + public double? StartTimeMs { get; set; } + + /// Session timeout in milliseconds. + [JsonPropertyName("timeoutMs")] + public double? TimeoutMs { get; set; } + + /// Redacted validation and memory-tool settings. + [JsonPropertyName("validation")] + public SessionSettingsValidationSnapshot Validation { get => field ??= new(); set; } + + /// Agent runtime version selector copied from the session settings, such as `latest` or a runtime release identifier. + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Toggles whether permission prompts should be bridged into session events for this client. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsSetRequiredRequest +internal sealed class SessionSettingsSnapshotRequest { - /// Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). - [JsonPropertyName("required")] - public bool Required { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// Result of evaluating a Rust-owned settings predicate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsResetSessionApprovalsResult +internal sealed class SessionSettingsEvaluatePredicateResult { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the named settings predicate evaluated to enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } } -/// Clears session-scoped tool approvals and optionally clears location-scoped approvals and exact session-approved paths. +/// Named Rust-owned settings predicate to evaluate for this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsResetSessionApprovalsRequest +internal sealed class SessionSettingsEvaluatePredicateRequest { - /// Whether location-scoped approvals and exact session-approved paths are cleared too. Defaults to `true`. - [JsonPropertyName("includeLocation")] - public bool? IncludeLocation { get; set; } + /// Predicate name. The runtime owns the raw feature-flag names and composition logic. + [JsonPropertyName("name")] + public SessionSettingsPredicateName Name { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Tool name for tool-scoped predicates such as trivial-change handling. + [JsonPropertyName("toolName")] + public string? ToolName { get; set; } } -/// Indicates whether the operation succeeded. +/// Content-exclusion decision for one requested path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsNotifyPromptShownResult +public sealed class ContentExclusionPathCheck { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the session's complete content-exclusion policy excludes the path. + [JsonPropertyName("excluded")] + public bool Excluded { get; set; } + + /// The path supplied by the caller. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Notification payload describing the permission prompt that the client just rendered. +/// Batch content-exclusion result. Callers must fail closed when policy evaluation is unavailable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPromptShownNotification +public sealed class ContentExclusionCheckPathsResult { - /// Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Whether the session's policy service was available for the complete batch. When false, checks is empty and callers must treat every requested path as excluded. + [JsonPropertyName("available")] + public bool Available { get; set; } + + /// Per-path decisions in request order. Empty when available is false. + [JsonPropertyName("checks")] + public IList Checks { get => field ??= []; set; } +} + +/// Local file system absolute paths within the session working directory to check against its content-exclusion policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ContentExclusionCheckPathsRequest +{ + /// Local file system absolute paths within the session working directory to check. Results are returned in the same order, including duplicates. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Snapshot of the session's recursive directory grants, exact session-approved paths, and primary working directory. +/// Identifier of the spawned shell process, usable with shell.kill while the process is running. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsList +public sealed class ShellExecResult { - /// All directories currently allowed for tool access on this session. - [JsonPropertyName("directories")] - public IList Directories { get => field ??= []; set; } + /// Identifier usable with shell.kill while the process is running. + [JsonPropertyName("processId")] + public string ProcessId { get; set; } = string.Empty; +} - /// The primary working directory for this session. - [JsonPropertyName("primary")] - public string Primary { get; set; } = string.Empty; +/// Shell command to run, with optional working directory and timeout in milliseconds. Spawn failures return an RPC error. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ShellExecRequest +{ + /// Shell command to execute. + [JsonPropertyName("command")] + public string Command { get; set; } = string.Empty; - /// Exact paths approved for this session without recursively allowing their descendants. - [JsonPropertyName("sessionApprovedPaths")] - public IList? SessionApprovedPaths { get; set; } -} + /// Working directory (defaults to session working directory). + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } -/// No parameters; returns the session's recursive directory grants and exact session-approved paths. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsPathsListRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Timeout in milliseconds (default: 30000). + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonPropertyName("timeout")] + public TimeSpan? Timeout { get; set; } } -/// Indicates whether the operation succeeded. +/// Indicates whether the signal was delivered; false if the process was unknown or already exited. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsPathsAddResult +public sealed class ShellKillResult { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the signal was sent successfully. + [JsonPropertyName("killed")] + public bool Killed { get; set; } } -/// Directory path to add to the session's allowed directories. +/// Identifier of a process previously returned by "shell.exec" and the signal to send. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsAddParams +internal sealed class ShellKillRequest { - /// Directory to add to the allow-list. The runtime resolves and validates the path before adding, then loads conventional `.github/skills/` and `.github/agents/` definitions under it when their subsystem gates are enabled. Adding the directory is therefore also a trust decision for configuration stored there. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Process identifier returned by shell.exec. + [JsonPropertyName("processId")] + public string ProcessId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Signal to send (default: SIGTERM). + [JsonPropertyName("signal")] + public ShellKillSignal? Signal { get; set; } } -/// Indicates whether the operation succeeded. +/// Result of a user-requested shell command. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsPathsUpdatePrimaryResult +public sealed class UserRequestedShellCommandResult { - /// Whether the operation succeeded. + /// Error output when the execution failed. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Process exit code, when available. + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } + + /// Captured command output. + [JsonPropertyName("output")] + public string Output { get; set; } = string.Empty; + + /// Whether the command completed successfully. [JsonPropertyName("success")] public bool Success { get; set; } + + /// Tool call id emitted for the shell execution. + [JsonPropertyName("toolCallId")] + public string ToolCallId { get; set; } = string.Empty; } -/// Directory path to set as the session's new primary working directory. +/// User-requested shell command and cancellation handle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsUpdatePrimaryParams +internal sealed class ShellExecuteUserRequestedRequest { - /// Directory to set as the new primary working directory for the session's permission policy. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Shell command to execute. + [JsonPropertyName("command")] + public string Command { get; set; } = string.Empty; + + /// Caller-provided cancellation handle for this execution. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the supplied path is within the session's allowed directories. +/// Cancellation result for a user-requested shell command. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsAllowedCheckResult +public sealed class CancelUserRequestedShellCommandResult { - /// Whether the path is within the session's allowed directories. - [JsonPropertyName("allowed")] - public bool Allowed { get; set; } + /// Whether an in-flight execution was found and signalled to cancel. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } } -/// Path to evaluate against the session's allowed directories. +/// User-requested shell execution cancellation handle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsAllowedCheckParams +internal sealed class ShellCancelUserRequestedRequest { - /// Path to check against the session's allowed directories. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Request ID previously passed to executeUserRequested. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the supplied path is within the session's workspace directory. +/// Post-compaction context window usage breakdown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsWorkspaceCheckResult +public sealed class HistoryCompactContextWindow { - /// Whether the path is within the session workspace directory. - [JsonPropertyName("allowed")] - public bool Allowed { get; set; } + /// Token count from non-system messages (user, assistant, tool). + [JsonPropertyName("conversationTokens")] + public long? ConversationTokens { get; set; } + + /// Current total tokens in the context window (system + conversation + tool definitions). + [JsonPropertyName("currentTokens")] + public long CurrentTokens { get; set; } + + /// Current number of messages in the conversation. + [JsonPropertyName("messagesLength")] + public long MessagesLength { get; set; } + + /// Token count from system message(s). + [JsonPropertyName("systemTokens")] + public long? SystemTokens { get; set; } + + /// Maximum token count for the model's context window. + [JsonPropertyName("tokenLimit")] + public long TokenLimit { get; set; } + + /// Token count from tool definitions. + [JsonPropertyName("toolDefinitionsTokens")] + public long? ToolDefinitionsTokens { get; set; } } -/// Path to evaluate against the session's workspace (primary) directory. +/// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsWorkspaceCheckParams +public sealed class HistoryCompactResult { - /// Path to check against the session workspace directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Post-compaction context window usage breakdown. + [JsonPropertyName("contextWindow")] + public HistoryCompactContextWindow? ContextWindow { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Number of messages removed during compaction. + [JsonPropertyName("messagesRemoved")] + public long MessagesRemoved { get; set; } + + /// Whether compaction completed successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } + + /// Summary text produced by compaction. Omitted when compaction did not produce a summary (e.g. failure path). + [JsonPropertyName("summaryContent")] + public string? SummaryContent { get; set; } + + /// Number of tokens freed by compaction. + [JsonPropertyName("tokensRemoved")] + public long TokensRemoved { get; set; } } -/// Resolved location-permissions key and type. +/// RPC data type for SessionHistoryCompact operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionLocationResolveResult +public sealed class SessionHistoryCompactRequest { - /// Location key used in the location-permissions store. - [JsonPropertyName("locationKey")] - public string LocationKey { get; set; } = string.Empty; + /// Optional user-provided instructions to focus the compaction summary. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(4000)] + [JsonPropertyName("customInstructions")] + public string? CustomInstructions { get; set; } - /// Whether the location is a git repo or directory. - [JsonPropertyName("locationType")] - public PermissionLocationType LocationType { get; set; } + /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. + [JsonPropertyName("tokenLimit")] + public long? TokenLimit { get; set; } + + /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). + [JsonPropertyName("trigger")] + public SessionHistoryCompactRequestTrigger? Trigger { get; set; } } -/// Working directory to resolve into a location-permissions key. +/// RPC data type for SessionHistoryCompactRequestWithSession operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionLocationResolveParams +internal sealed class SessionHistoryCompactRequestWithSession { + /// Optional user-provided instructions to focus the compaction summary. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(4000)] + [JsonPropertyName("customInstructions")] + public string? CustomInstructions { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Working directory whose permission location should be resolved. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; + /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. + [JsonPropertyName("tokenLimit")] + public long? TokenLimit { get; set; } + + /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). + [JsonPropertyName("trigger")] + public SessionHistoryCompactRequestTrigger? Trigger { get; set; } } -/// Summary of persisted location permissions applied to the session. +/// Number of events that were removed by the truncation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionLocationApplyResult +public sealed class HistoryTruncateResult { - /// Number of persisted allowed directories added to the live path manager. - [JsonPropertyName("appliedDirectoryCount")] - public long AppliedDirectoryCount { get; set; } - - /// Number of location-scoped rules added to the live permission service. - [JsonPropertyName("appliedRuleCount")] - public long AppliedRuleCount { get; set; } - - /// Location-scoped rules applied to the live permission service. - [JsonPropertyName("appliedRules")] - public IList AppliedRules { get => field ??= []; set; } - - /// Whether a different location was applied since the previous apply call. - [JsonPropertyName("changed")] - public bool Changed { get; set; } + /// Failure detail when checkpointCleanupFailed is true. + [JsonPropertyName("checkpointCleanupError")] + public string? CheckpointCleanupError { get; set; } - /// Location key used in the location-permissions store. - [JsonPropertyName("locationKey")] - public string LocationKey { get; set; } = string.Empty; + /// True when conversation truncation succeeded but post-truncation workspace checkpoint cleanup failed. History is already truncated; callers may still prune snapshots but should report a checkpoint-cleanup rather than a truncation failure. + [JsonPropertyName("checkpointCleanupFailed")] + public bool? CheckpointCleanupFailed { get; set; } - /// Whether the location is a git repo or directory. - [JsonPropertyName("locationType")] - public PermissionLocationType LocationType { get; set; } + /// Number of events that were removed. + [JsonPropertyName("eventsRemoved")] + public long EventsRemoved { get; set; } } -/// Working directory to load persisted location permissions for. +/// Identifier of the event to truncate to; this event and all later events are removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionLocationApplyParams +internal sealed class HistoryTruncateRequest { + /// Event ID to truncate to. This event and all events after it are removed from the session. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Working directory whose persisted location permissions should be applied. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// A root user turn that the session can rewind to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsLocationsAddToolApprovalResult +public sealed class HistoryRewindPoint { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// Whether at least one file in this turn or a later turn can be restored. + [JsonPropertyName("canRestoreFiles")] + public bool CanRestoreFiles { get; set; } -/// Tool approval to persist and apply. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCommands), "commands")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsRead), "read")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWrite), "write")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcp), "mcp")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcpSampling), "mcp-sampling")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMemory), "memory")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCustomTool), "custom-tool")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionManagement), "extension-management")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWorkflow), "workflow")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess), "extension-permission-access")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess), "extension-env-access")] -public partial class PermissionsLocationsAddToolApprovalDetails -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// ID of the user.message event that begins the discarded suffix. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; + /// Number of unique files in this turn and all later turns that have captured changes. + [JsonPropertyName("fileCount")] + public long FileCount { get; set; } -/// Location-persisted tool approval details for specific command identifiers. -/// The commands variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsCommands : PermissionsLocationsAddToolApprovalDetails -{ - /// - [JsonIgnore] - public override string Kind => "commands"; + /// Whether this turn was an automatically injected autopilot continuation. + [JsonPropertyName("isAutopilotContinuation")] + public bool IsAutopilotContinuation { get; set; } - /// Command identifiers covered by this approval. - [JsonPropertyName("commandIdentifiers")] - public required IList CommandIdentifiers { get; set; } + /// Lines added by this turn's captured file changes. + [JsonPropertyName("linesAdded")] + public long LinesAdded { get; set; } + + /// Lines removed by this turn's captured file changes. + [JsonPropertyName("linesRemoved")] + public long LinesRemoved { get; set; } + + /// ISO timestamp of the user turn. + [JsonPropertyName("timestamp")] + public string Timestamp { get; set; } = string.Empty; + + /// Whether this turn itself captured any file changes. + [JsonPropertyName("turnChangedFiles")] + public bool TurnChangedFiles { get; set; } + + /// User-visible message text for the turn. + [JsonPropertyName("userMessage")] + public string UserMessage { get; set; } = string.Empty; } -/// Location-persisted tool approval details for read-only filesystem operations. -/// The read variant of . +/// Rewind points and file-change-tracking availability for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsRead : PermissionsLocationsAddToolApprovalDetails +public sealed class HistoryListRewindPointsResult { - /// - [JsonIgnore] - public override string Kind => "read"; + /// Whether this session captured file changes from its first turn. + [JsonPropertyName("fileChangeTrackingEnabled")] + public bool FileChangeTrackingEnabled { get; set; } + + /// Root user turns in chronological order. Empty when `unavailableReason` is set. + [JsonPropertyName("points")] + public IList Points { get => field ??= []; set; } + + /// Why the listed points could not be produced, when applicable; the points list is empty whenever it is set. `unsupported-remote-session` is permanent for the session and comes with `fileChangeTrackingEnabled: false`. `session-busy` is transient and only ever reported by a session that *is* tracking (`fileChangeTrackingEnabled: true`), because the file-change captures cannot be read while work that may still mutate them is in flight; the same request succeeds once the session settles, so a client that wants points should retry rather than treat it as a failure. It is never `file-change-tracking-disabled`: an untracked local session still lists conversation-only points and reports that through `fileChangeTrackingEnabled: false`. + [JsonPropertyName("unavailableReason")] + public HistoryRewindUnavailableReason? UnavailableReason { get; set; } } -/// Location-persisted tool approval details for filesystem write operations. -/// The write variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsWrite : PermissionsLocationsAddToolApprovalDetails +internal sealed class SessionHistoryListRewindPointsRequest { - /// - [JsonIgnore] - public override string Kind => "write"; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-persisted tool approval details for an MCP server tool, or all tools when `toolName` is null. -/// The mcp variant of . +/// A file that a conversation-and-files rewind would restore. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsMcp : PermissionsLocationsAddToolApprovalDetails +public sealed class HistoryRewindFilePreview { - /// - [JsonIgnore] - public override string Kind => "mcp"; + /// Aggregate change made across the discarded turns. + [JsonPropertyName("changeType")] + public HistoryRewindChangeType ChangeType { get; set; } - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Lines added across the discarded turns. + [JsonPropertyName("linesAdded")] + public long LinesAdded { get; set; } - /// MCP tool name, or null to cover every tool on the server. - [JsonPropertyName("toolName")] - public string? ToolName { get; set; } + /// Lines removed across the discarded turns. + [JsonPropertyName("linesRemoved")] + public long LinesRemoved { get; set; } + + /// Absolute path of the captured file. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Location-persisted tool approval details for MCP sampling requests from a server. -/// The mcp-sampling variant of . +/// Files and aggregate changes for a prospective rewind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsMcpSampling : PermissionsLocationsAddToolApprovalDetails +public sealed class HistoryPreviewRewindResult { - /// - [JsonIgnore] - public override string Kind => "mcp-sampling"; + /// Whether file restore is available for this session. This is authoritative: switch on it and read `reason` only when it is false. + [JsonPropertyName("available")] + public bool Available { get; set; } - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } -} + /// Number of unique files in the preview. + [JsonPropertyName("fileCount")] + public long FileCount { get; set; } -/// Location-persisted tool approval details for writes to long-term memory. -/// The memory variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsMemory : PermissionsLocationsAddToolApprovalDetails -{ - /// - [JsonIgnore] - public override string Kind => "memory"; + /// Files ordered by path. + [JsonPropertyName("files")] + public IList Files { get => field ??= []; set; } + + /// Why file restore is unavailable, when applicable. Populated only when `available` is false and never set when `available` is true. + [JsonPropertyName("reason")] + public HistoryRewindUnavailableReason? Reason { get; set; } } -/// Location-persisted tool approval details for a custom tool, keyed by tool name. -/// The custom-tool variant of . +/// Event boundary to preview for conversation-and-files rewind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsCustomTool : PermissionsLocationsAddToolApprovalDetails +internal sealed class HistoryPreviewRewindRequest { - /// - [JsonIgnore] - public override string Kind => "custom-tool"; + /// ID of the user.message event that begins the discarded suffix. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; - /// Custom tool name. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-persisted tool approval details for extension-management operations, optionally narrowed by operation. -/// The extension-management variant of . +/// A captured file that rewind intentionally left unchanged. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsExtensionManagement : PermissionsLocationsAddToolApprovalDetails +public sealed class HistorySkippedFileRestore { - /// - [JsonIgnore] - public override string Kind => "extension-management"; + /// Absolute path of the skipped file. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Optional operation identifier; when omitted, the approval covers all extension management operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operation")] - public string? Operation { get; set; } + /// Reason the file was not restored. + [JsonPropertyName("reason")] + public HistoryFileRestoreSkipReason Reason { get; set; } } -/// Location-persisted workflow approval, optionally narrowed by approval key. -/// The workflow variant of . +/// Structured outcome of a rewind request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsWorkflow : PermissionsLocationsAddToolApprovalDetails +public sealed class HistoryRewindResult { - /// - [JsonIgnore] - public override string Kind => "workflow"; + /// Failure detail. Set only for the failure and partial-failure outcomes (`files-rolled-back`, `rollback-incomplete`, `truncation-failed`, `checkpoint-cleanup-failed`, `snapshot-prune-failed`); omitted for `success` and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`). + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approvalKey")] - public string? ApprovalKey { get; set; } -} + /// Number of persisted events removed by conversation truncation. Present only when truncation succeeded (outcomes `success`, `checkpoint-cleanup-failed`, and `snapshot-prune-failed`); omitted for every unavailable outcome (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`) and for `truncation-failed`, `files-rolled-back`, and `rollback-incomplete`. + [JsonPropertyName("eventsRemoved")] + public long? EventsRemoved { get; set; } -/// Location-persisted tool approval details for an extension's permission-gated capability access, keyed by extension name. -/// The extension-permission-access variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess : PermissionsLocationsAddToolApprovalDetails -{ - /// - [JsonIgnore] - public override string Kind => "extension-permission-access"; + /// Overall rewind outcome. This discriminates the result: it governs which of the remaining fields are populated, so consumers must switch on it before reading `eventsRemoved`, `restoredFiles`, `skippedFiles`, or `error`. See each field for the outcomes that populate it. + [JsonPropertyName("outcome")] + public HistoryRewindOutcome Outcome { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } + /// Absolute paths restored to their captured preimages. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. + [JsonPropertyName("restoredFiles")] + public IList RestoredFiles { get => field ??= []; set; } + + /// Captured files intentionally left unchanged. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. + [JsonPropertyName("skippedFiles")] + public IList SkippedFiles { get => field ??= []; set; } } -/// Location-persisted tool approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. -/// The extension-env-access variant of . +/// Boundary and mode for rewinding session history. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess : PermissionsLocationsAddToolApprovalDetails +internal sealed class HistoryRewindRequest { - /// - [JsonIgnore] - public override string Kind => "extension-env-access"; + /// ID of the user.message event that begins the discarded suffix. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; - /// Names of the sensitive environment variables this approval covers. Values are never persisted. - [JsonPropertyName("environmentVariables")] - public required IList EnvironmentVariables { get; set; } + /// Whether to rewind only conversation history or also restore captured files. + [JsonPropertyName("mode")] + public HistoryRewindMode Mode { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-scoped tool approval to persist. +/// Indicates whether an in-progress background compaction was cancelled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionLocationAddToolApprovalParams +public sealed class HistoryCancelBackgroundCompactionResult { - /// Tool approval to persist and apply. - [JsonPropertyName("approval")] - public PermissionsLocationsAddToolApprovalDetails Approval { get => field ??= new(); set; } - - /// Location key (git root or cwd) to persist the approval to. - [JsonPropertyName("locationKey")] - public string LocationKey { get; set; } = string.Empty; + /// Whether an in-progress background compaction was cancelled. False when no compaction was running, when the session is remote, or when the underlying processor was unavailable. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionHistoryCancelBackgroundCompactionRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Folder trust check result. +/// Indicates whether an in-progress manual compaction was aborted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class FolderTrustCheckResult +public sealed class HistoryAbortManualCompactionResult { - /// Whether the folder is trusted. - [JsonPropertyName("trusted")] - public bool Trusted { get; set; } + /// Whether an in-progress manual compaction was aborted. False when no manual compaction was running, when its abort controller was already aborted, or when the session is remote. + [JsonPropertyName("aborted")] + public bool Aborted { get; set; } } -/// Folder path to check for trust. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FolderTrustCheckParams +internal sealed class SessionHistoryAbortManualCompactionRequest { - /// Folder path to check. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// Markdown summary of the conversation context (empty when not available). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsFolderTrustAddTrustedResult +public sealed class HistorySummarizeForHandoffResult { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Markdown summary of the conversation context produced by an LLM. Empty string when there are no messages or when the session does not support local summarization. + [JsonPropertyName("summary")] + public string Summary { get; set; } = string.Empty; } -/// Folder path to add to trusted folders. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FolderTrustAddParams +internal sealed class SessionHistorySummarizeForHandoffRequest { - /// Folder path to mark as trusted. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// What a successful clear removed. A clear that could not be applied rejects instead of reporting a count. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsUrlsSetUnrestrictedModeResult +public sealed class HistoryClearContextResult { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Number of non-system, non-developer messages that were removed from the conversation. Zero only when the window already held no conversation. + [JsonPropertyName("messagesCleared")] + public long MessagesCleared { get; set; } } -/// Whether the URL-permission policy should run in unrestricted mode. +/// Parameters for clearing the conversation and seeding the window that replaces it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionUrlsSetUnrestrictedModeParams +internal sealed class HistoryClearContextRequest { - /// Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// First user message of the fresh context window. Required: a cleared window holding only system and developer messages is not a conversation a model can answer, so every clear seeds the window it creates. Delivered by the enclosing turn driver once the agentic loop exits, which is why the call must be made from inside a tool handler. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The repository the remote session targets. +/// User-facing pending queue entry, with kind and display text for a queued message, slash command, or model change. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataSnapshotRemoteMetadataRepository +public sealed class QueuePendingItems { - /// The branch the remote session is operating on. - [JsonPropertyName("branch")] - public string Branch { get; set; } = string.Empty; + /// Agent mode stored on this queued entry, as stamped when it was enqueued. Items without an explicit mode report interactive. This is not necessarily the mode that will constrain the turn: a plan or autopilot session applies its own write gate, continuation loop and permission posture to every drained item regardless of the mode stored here. + [JsonPropertyName("agentMode")] + public SendAgentMode AgentMode { get; set; } - /// The GitHub repository name (without owner). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Human-readable text to display for this queue entry in the UI. + [JsonPropertyName("displayText")] + public string DisplayText { get; set; } = string.Empty; - /// The GitHub owner (user or organization) of the target repository. - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; + /// Stable opaque id for the canonical queued item. Batch rows share one id. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Whether this item is a queued user message or a queued slash command / model change. + [JsonPropertyName("kind")] + public QueuePendingItemsKind Kind { get; set; } + + /// Stable identity of the queued user message. Present for message rows and absent for slash commands and model changes. + [JsonPropertyName("messageId")] + public string? MessageId { get; set; } + + /// Optional source tag associated with this pending queue entry. This is an open string, not authenticated authorship. In particular, `user` does not prove that a person typed the message. If the source is absent or unrecognized, consumers must not infer human or agent authorship and should handle the entry neutrally. Consumers should tolerate future source values. + [JsonPropertyName("source")] + public string? Source { get; set; } } -/// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. +/// Snapshot of the session's pending queued items and immediate-steering messages. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataSnapshotRemoteMetadata +public sealed class QueuePendingItemsResult { - /// The pull request number the remote session is associated with, if any. - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } + /// How many leading entries of `steeringMessages` have already been folded into the running turn (and so have an emitted `user.message`), as opposed to still waiting for one. Absent for hosts that do not distinguish the two. + [JsonPropertyName("inFlightSteeringCount")] + public long? InFlightSteeringCount { get; set; } - /// The repository the remote session targets. - [JsonPropertyName("repository")] - public MetadataSnapshotRemoteMetadataRepository Repository { get => field ??= new(); set; } + /// Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } - /// The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Display text for messages currently in the immediate steering queue (interjections sent during a running turn). + [JsonPropertyName("steeringMessages")] + public IList SteeringMessages { get => field ??= []; set; } - /// Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. - [JsonPropertyName("taskType")] - public MetadataSnapshotRemoteMetadataTaskType? TaskType { get; set; } + /// ID of the running turn's user message while the model has not answered it, so `withdrawMessage` can still take it back once nothing sent after it is pending. A message leaves `items` when its turn starts, before its `user.message` is recorded; this tells that message apart from one that was removed. Absent when no turn prompt can be taken back. + [JsonPropertyName("withdrawableTurnMessageId")] + public string? WithdrawableTurnMessageId { get; set; } } -/// Public-facing projection of workspace metadata for SDK / TUI consumers. -public sealed class SessionMetadataSnapshotWorkspace +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionQueuePendingItemsRequest { - /// Branch checked out at session start, if any. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// ISO 8601 timestamp when the workspace was created. - [JsonPropertyName("created_at")] - public DateTimeOffset? CreatedAt { get; set; } - - /// Current working directory at session start. - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Resolved git root for cwd, if any. - [JsonPropertyName("git_root")] - public string? GitRoot { get; set; } +/// Internal snapshot of native queue state for local session orchestration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueSnapshotResult +{ + /// Queue item identifier of a model switch that has been dequeued but not yet applied. + [JsonPropertyName("inFlightModelChangeId")] + public string? InFlightModelChangeId { get; set; } - /// Repository host type, if known. - [JsonPropertyName("host_type")] - public WorkspaceSummaryHostType? HostType { get; set; } + /// Insertion orders for queued items, aligned with `items`. + [JsonPropertyName("itemOrders")] + public IList? ItemOrders { get; set; } - /// Workspace identifier (1:1 with sessionId). - [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("id")] - public string Id { get; set; } = string.Empty; + /// User-facing pending items in FIFO order. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } - /// Display name for the session, if set. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Insertion orders for immediate steering messages, aligned with `steeringMessages`. + [JsonPropertyName("steeringMessageOrders")] + public IList? SteeringMessageOrders { get; set; } - /// Repository identifier in 'owner/repo' or 'org/project/repo' format, if any. - [JsonPropertyName("repository")] - public string? Repository { get; set; } + /// Immediate steering messages waiting for an active turn. + [JsonPropertyName("steeringMessages")] + public IList SteeringMessages { get => field ??= []; set; } +} - /// ISO 8601 timestamp when the workspace was last updated. - [JsonPropertyName("updated_at")] - public DateTimeOffset? UpdatedAt { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionQueueSnapshotRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether the display name was explicitly set by the user. - [JsonPropertyName("user_named")] - public bool? UserNamed { get; set; } +/// Result of moving a queued item. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueMoveItemResult +{ + /// True when the item changed position; false when it was already at the requested position. + [JsonPropertyName("changed")] + public bool Changed { get; set; } } -/// Point-in-time snapshot of slow-changing session identifier and state fields. +/// Parameters for moving a queued item by stable id. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionMetadataSnapshot +internal sealed class QueueMoveItemRequest { - /// True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. - [JsonPropertyName("alreadyInUse")] - public bool AlreadyInUse { get; set; } + /// Stable opaque queued-item id. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Runtime client name associated with the session (telemetry identifier). - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot'). - [JsonPropertyName("currentMode")] - public MetadataSnapshotCurrentMode CurrentMode { get; set; } + /// Zero-based target position in the public visible queue. Values outside the queue clamp to an end. + [JsonPropertyName("toPosition")] + public long ToPosition { get; set; } +} - /// Live indexed-search state for this session activation. Omitted by runtimes that do not expose indexed-search status; absence does not indicate enablement. - [JsonPropertyName("indexedSearch")] - public IndexedSearchState? IndexedSearch { get; set; } +/// Result of inserting a queued message. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueInsertAtResult +{ + /// Fresh stable opaque id assigned to the inserted item. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; +} - /// User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. - [JsonPropertyName("initialName")] - public string? InitialName { get; set; } +/// Serializable message fields accepted by queue.insertAt. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueInsertMessage +{ + /// Optional explicit agent mode. When omitted, the session's current mode is assigned. + [JsonPropertyName("agentMode")] + public SendAgentMode? AgentMode { get; set; } - /// Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process). - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } + /// Optional attachments for the message. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } - /// ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. - [JsonPropertyName("modifiedTime")] - public DateTimeOffset ModifiedTime { get; set; } + /// Whether the message is billable. + [JsonPropertyName("billable")] + public bool? Billable { get; set; } - /// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. - [JsonPropertyName("remoteMetadata")] - public MetadataSnapshotRemoteMetadata? RemoteMetadata { get; set; } + /// Accepted for internal SendOptions compatibility but ignored; delivery is derived from current session activity. + [JsonPropertyName("delivery")] + public string? Delivery { get; set; } - /// Currently selected model identifier, if any. - [JsonPropertyName("selectedModel")] - public string? SelectedModel { get; set; } + /// Optional user-facing display text. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// The unique identifier of the session. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Accepted for SendOptions compatibility but ignored; inserted items always use queued delivery semantics. + [JsonPropertyName("mode")] + public SendMode? Mode { get; set; } - /// Current session limits, or null when no limits are active. - [JsonPropertyName("sessionLimits")] - public SessionLimitsConfig? SessionLimits { get; set; } + /// Accepted for SendOptions compatibility but ignored; the requested public position controls placement. + [JsonPropertyName("prepend")] + public bool? Prepend { get; set; } - /// ISO 8601 timestamp of when the session started. - [JsonPropertyName("startTime")] - public DateTimeOffset StartTime { get; set; } + /// The user message text. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Short human-readable summary of the session, if known. Omitted when no summary has been generated. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// Per-turn request headers. + [JsonPropertyName("requestHeaders")] + public IDictionary? RequestHeaders { get; set; } - /// Absolute path to the session's current working directory. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; + /// Required tool name for the turn, when any. + [JsonPropertyName("requiredTool")] + public string? RequiredTool { get; set; } - /// Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). - [JsonPropertyName("workspace")] - public SessionMetadataSnapshotWorkspace? Workspace { get; set; } + /// Optional provenance source. `system` is rejected: it would hide the inserted row from `pendingItems` and make it unaddressable while still executing, so inserted items must stay visible. + [JsonPropertyName("source")] + public string? Source { get; set; } - /// Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace. - [JsonPropertyName("workspacePath")] - public string? WorkspacePath { get; set; } + /// Accepted for SendOptions compatibility but ignored; insertion scheduling is controlled by the queue drain state. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } } -/// Identifies the target session. +/// Parameters for inserting a queued message at a public visible position. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataSnapshotRequest +internal sealed class QueueInsertAtRequest { + /// Queued message contents and delivery metadata. + [JsonPropertyName("message")] + public QueueInsertMessage Message { get => field ??= new(); set; } + + /// Zero-based position in the public visible queue. Values outside the queue clamp to an end. + [JsonPropertyName("position")] + public long Position { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Result of removing a queued item. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataGetClientMetadataRequest +public sealed class QueueRemoveAtResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// True when the addressed item was removed. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } -/// Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes. +/// Parameters for removing a queued item by stable id. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataUpdateClientMetadataRequest +internal sealed class QueueRemoveAtRequest { - /// Remove every existing client metadata entry before applying remove and set. Defaults to false. - [JsonPropertyName("clear")] - public bool? Clear { get; set; } - - /// Case-sensitive keys to remove. Missing keys are ignored. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. - [JsonPropertyName("remove")] - public IList? Remove { get; set; } + /// Stable opaque ID of the queued item to remove. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// String entries to add or replace. Set wins when a key also appears in remove. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Each value may contain at most 16 KiB of UTF-8 data. - [JsonPropertyName("set")] - public IDictionary? Set { get; set; } } -/// Indicates whether the local session is currently processing a turn or background continuation. +/// Result of editing a queued message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataIsProcessingResult +public sealed class QueueUpdateTextResult { - /// Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. - [JsonPropertyName("processing")] - public bool Processing { get; set; } + /// True when the stored text changed. + [JsonPropertyName("updated")] + public bool Updated { get; set; } } -/// Identifies the target session. +/// Parameters for editing a single queued message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataIsProcessingRequest +internal sealed class QueueUpdateTextRequest { + /// Optional replacement prompt displayed to the user. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } + + /// Stable opaque ID of the queued item to edit. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Replacement prompt sent to the model. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Current activity flags for the session. +/// Result of withdrawing a user message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionActivity +public sealed class QueueWithdrawMessageResult { - /// Whether an in-flight operation can currently be aborted. - [JsonPropertyName("abortable")] - public bool Abortable { get; set; } + /// True when the running turn was interrupted to withdraw the message. With removed false, the turn was interrupted but its events could not be removed, for example because the model answered first, so the message stays in the interrupted turn. + [JsonPropertyName("interrupted")] + public bool Interrupted { get; set; } - /// Whether the session currently has active work, including running turns or tasks. - [JsonPropertyName("hasActiveWork")] - public bool HasActiveWork { get; set; } + /// True when the message left the queue or, for a running turn, history. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } -/// Identifies the target session. +/// Conditional withdrawal of a single user message, from its queue or from the running turn it started. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataActivityRequest +internal sealed class QueueWithdrawMessageRequest { + /// The prompt originally sent. A message edited since submission is not withdrawn, so an obsolete draft cannot replace the edit. + [JsonPropertyName("expectedPrompt")] + public string ExpectedPrompt { get; set; } = string.Empty; + + /// Message identity returned by send, not the queue item id. Batch messages are not eligible. + [JsonPropertyName("messageId")] + public string MessageId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Token-usage breakdown for the session's current context window. -public sealed class MetadataContextInfoResultContextInfo +/// Append to one pending steering message without changing its identity or delivery position. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueAppendSteeringRequest { - /// Output reserve plus tokens after the buffer-exhaustion blocking threshold (default 95%). - [JsonPropertyName("bufferTokens")] - public long BufferTokens { get; set; } + /// Mode captured at submission. Only steering messages in the same mode may be combined. + [JsonPropertyName("agentMode")] + public SendAgentMode AgentMode { get; set; } - /// Token count at which background compaction starts (configurable percentage of promptTokenLimit). - [JsonPropertyName("compactionThreshold")] - public long CompactionThreshold { get; set; } + /// Attachments to add after the message's existing attachments. An empty list preserves the existing attachments. + [JsonPropertyName("attachments")] + public IList Attachments { get => field ??= []; set; } - /// Tokens consumed by user/assistant/tool messages. - [JsonPropertyName("conversationTokens")] - public long ConversationTokens { get; set; } + /// Display text to append to the existing preview after a blank line. + [JsonPropertyName("displayPrompt")] + public string DisplayPrompt { get; set; } = string.Empty; - /// Prompt token limit plus the model's full output token limit. - [JsonPropertyName("limit")] - public long Limit { get; set; } + /// Expected current prompt, including any previous appends. The runtime applies plan-mode normalization before comparing and refuses a changed message. + [JsonPropertyName("expectedPrompt")] + public string ExpectedPrompt { get; set; } = string.Empty; - /// Tokens consumed by MCP tool definitions (subset of toolDefinitionsTokens, excludes deferred tools). - [JsonPropertyName("mcpToolsTokens")] - public long McpToolsTokens { get; set; } + /// Message identity returned by send, not the queue item id. Only unclaimed user steering messages are eligible. + [JsonPropertyName("messageId")] + public string MessageId { get; set; } = string.Empty; - /// The model used for token counting. - [JsonPropertyName("modelName")] - public string ModelName { get; set; } = string.Empty; + /// Text to append after a blank line. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Maximum prompt tokens allowed by the model (or DEFAULT_TOKEN_LIMIT if unspecified). - [JsonPropertyName("promptTokenLimit")] - public long PromptTokenLimit { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Tokens consumed by the system prompt. - [JsonPropertyName("systemTokens")] - public long SystemTokens { get; set; } +/// Result of duplicating a queued item. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueDuplicateAtResult +{ + /// Fresh stable opaque id assigned to the duplicate. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; +} - /// Tokens consumed by tool definitions sent to the model (excludes deferred tools). - [JsonPropertyName("toolDefinitionsTokens")] - public long ToolDefinitionsTokens { get; set; } +/// Parameters for duplicating a queued item. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueDuplicateAtRequest +{ + /// Stable opaque ID of the queued item to duplicate. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Sum of system, conversation and tool-definition tokens. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Parameters for acquiring or releasing the queued-lane drain pause. Acquisition is exclusive and non-idempotent: `paused: true` against an already-paused session fails with `queue_already_paused`. The pause is never released automatically — it is not tied to the caller's lifetime, so a client that exits without sending `paused: false` leaves the lane frozen. Release is unowned: `paused: false` clears the pause for any caller, including one that never acquired it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueSetDrainPausedRequest +{ + /// Whether queued-lane draining should be paused. + [JsonPropertyName("paused")] + public bool Paused { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Result of trying to steer a queued message into a live turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueSendNowResult +{ + /// True when the item was accepted into the steering lane; false when no main turn was live. + [JsonPropertyName("steered")] + public bool Steered { get; set; } +} + +/// Parameters for steering a queued message into a live turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueSendNowRequest +{ + /// Stable opaque ID of the queued item to steer into the live turn. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Token breakdown for the session's current context window, or null if uninitialized. +/// Whether the native queue has pending work. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataContextInfoResult +internal sealed class QueueHasPendingResult { - /// Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). - [JsonPropertyName("contextInfo")] - public MetadataContextInfoResultContextInfo? ContextInfo { get; set; } + /// True when queued or immediate native work is pending. + [JsonPropertyName("hasPending")] + public bool HasPending { get; set; } } -/// Model identifier and token limits used to compute the context-info breakdown. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataContextInfoRequest +internal sealed class SessionQueueHasPendingRequest { - /// Maximum output tokens allowed by the target model. Pass 0 if unknown. - [JsonPropertyName("outputTokenLimit")] - public long OutputTokenLimit { get; set; } - - /// Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default. - [JsonPropertyName("promptTokenLimit")] - public long PromptTokenLimit { get; set; } - - /// Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. - [JsonPropertyName("selectedModel")] - public string? SelectedModel { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. -public sealed class MetadataContextAttributionResultContextAttributionCategories +/// Whether a deferred-idle drain should run. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueBeginDeferredIdleDrainResult { - /// Output reserve plus post-blocking-threshold buffer. - [JsonPropertyName("buffer")] - public long Buffer { get; set; } - - /// Custom-instructions tokens (0 when none are configured). - [JsonPropertyName("customInstructions")] - public long CustomInstructions { get; set; } - - /// Remaining unused window capacity (clamped at 0). - [JsonPropertyName("freeSpace")] - public long FreeSpace { get; set; } - - /// MCP tool-definition tokens. - [JsonPropertyName("mcpTools")] - public long McpTools { get; set; } - - /// Conversation (user/assistant/tool) message tokens. - [JsonPropertyName("messages")] - public long Messages { get; set; } - - /// System prompt tokens, excluding custom instructions. - [JsonPropertyName("systemPrompt")] - public long SystemPrompt { get; set; } - - /// Non-MCP tool-definition tokens. - [JsonPropertyName("systemTools")] - public long SystemTools { get; set; } + /// True when the host should run finishDeferredIdleDrain asynchronously. + [JsonPropertyName("shouldDrain")] + public bool ShouldDrain { get; set; } } -/// Successful compaction history for the session. -public sealed class MetadataContextAttributionResultContextAttributionCompactions +/// Inputs for starting a deferred-idle drain. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueBeginDeferredIdleDrainRequest { - /// Number of successful compactions in this session. - [JsonPropertyName("count")] - public long Count { get; set; } + /// Whether the host still has active background work. + [JsonPropertyName("activeBackgroundWork")] + public bool ActiveBackgroundWork { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// RPC data type for MetadataContextAttributionResultContextAttributionEntry operations. -public sealed class MetadataContextAttributionResultContextAttributionEntry +/// Action selected by the native deferred-idle drain. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueFinishDeferredIdleDrainResult { - /// Supplementary per-entry metadata (e.g. `messageCount`, `role`, `evictable`, `pluginSource`). Values are stringified; parse as needed and ignore unrecognized keys. - [JsonPropertyName("attributes")] - public IDictionary? Attributes { get; set; } - - /// Identifier for this entry, formed by joining its `kind` and source name (e.g. `tool:bash`, `skill:tmux`, `toolDefinition:bash`); unique within the snapshot. Use it to match the same entry across snapshots, to correlate with other APIs (skill/agent/MCP registries), and as the `parentId` target for nesting. Distinct from the human-facing `label`. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Source category for this entry. Not a closed set — tolerate unknown values. Known values today: `skill`, `subagent`, `mcpServer`, `tool`, `system`, `toolDefinition`, `plugin`. - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; - - /// Human-readable display label, e.g. `bash` or `skill: tmux`. Presentation-only; may be localized/reformatted without notice — do not key off it. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; - - /// Optional `id` of the parent entry: e.g. a `plugin` entry parenting its `skill`/`mcpServer` entries, or the `system` entry parenting `toolDefinition` entries. Omitted for top-level entries. - [JsonPropertyName("parentId")] - public string? ParentId { get; set; } + /// Whether the deferred idle was caused by an aborted foreground turn. + [JsonPropertyName("aborted")] + public bool Aborted { get; set; } - /// Token count currently in context attributable to this entry. - [JsonPropertyName("tokens")] - public long Tokens { get; set; } + /// One of none, processQueue, or emitSessionIdle. + [JsonPropertyName("action")] + public string Action { get; set; } = string.Empty; } -/// Per-source token attribution snapshot for the current context window. The heaviest individual messages are available separately via `metadata.getContextHeaviestMessages`. -public sealed class MetadataContextAttributionResultContextAttribution +/// Inputs for completing a deferred-idle drain. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueFinishDeferredIdleDrainRequest { - /// Output reserve plus the tokens past the buffer-exhaustion blocking threshold. Mirrors `SessionContextInfo.bufferTokens`. - [JsonPropertyName("bufferTokens")] - public long BufferTokens { get; set; } - - /// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. - [JsonPropertyName("categories")] - public MetadataContextAttributionResultContextAttributionCategories Categories { get => field ??= new(); set; } - - /// Successful compaction history for the session. - [JsonPropertyName("compactions")] - public MetadataContextAttributionResultContextAttributionCompactions Compactions { get => field ??= new(); set; } - - /// Token count at which background compaction starts. Mirrors `SessionContextInfo.compactionThreshold`. - [JsonPropertyName("compactionThreshold")] - public long CompactionThreshold { get; set; } - - /// Flat list of per-source attribution entries. Group by `kind` and render unrecognized kinds generically. Nesting and rollups are expressed via `parentId`. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } - - /// Prompt limit plus the model's output reserve: the full context window `categories.freeSpace` and `categories.buffer` are measured against. Mirrors `SessionContextInfo.limit`. - [JsonPropertyName("limit")] - public long Limit { get; set; } + /// Whether the host still has active background work. + [JsonPropertyName("activeBackgroundWork")] + public bool ActiveBackgroundWork { get; set; } - /// The concrete model id the entire breakdown was tokenized against (feeds the per-model token multiplier). Under `Auto` (Free/Student) this is the resolved model, not the literal `auto` sentinel, so totals are not undercounted. A single-model approximation of a potentially multi-model Auto session. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; + /// Whether native queued work remains. + [JsonPropertyName("hasPending")] + public bool HasPending { get; set; } - /// How `modelId` was chosen. Not a closed set — tolerate unknown values. Known values today: `autoResolved` (the model Auto resolved to), `selected` (the user's explicitly selected model), `default` (a fallback before any model is known). - [JsonPropertyName("modelSource")] - public string ModelSource { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Maximum prompt tokens the resolved model accepts — the denominator for a `##k/###k` context-usage display. Mirrors `SessionContextInfo.promptTokenLimit`. - [JsonPropertyName("promptTokenLimit")] - public long PromptTokenLimit { get; set; } +/// Inputs for marking session.idle deferred in native state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueDeferSessionIdleRequest +{ + /// Whether the deferred idle was caused by an aborted foreground turn. + [JsonPropertyName("aborted")] + public bool Aborted { get; set; } - /// Total token count of the current context window the entries are measured against (system message + conversation messages + tool definitions — the same total reported by /context). Divide an entry's `tokens` by this to derive its share. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Per-source attribution breakdown for the session's current context window, or null if uninitialized. +/// Indicates whether a user-facing pending item was removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataContextAttributionResult +public sealed class QueueRemoveMostRecentResult { - /// Per-source context-window attribution, or null if the session has not yet been initialized (no system prompt or tool metadata cached). - [JsonPropertyName("contextAttribution")] - public MetadataContextAttributionResultContextAttribution? ContextAttribution { get; set; } + /// True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataGetContextAttributionRequest +internal sealed class SessionQueueRemoveMostRecentRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A single large message currently in context. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ContextHeaviestMessage +internal sealed class SessionQueueClearRequest { - /// Stable identifier for this message within the snapshot. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Human-readable source label, e.g. `tool: bash` or `skill: tmux`. Presentation-only. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; - - /// Role of the chat message (`user`, `assistant`, or `tool`). - [JsonPropertyName("role")] - public string Role { get; set; } = string.Empty; - - /// Token count currently in context for this individual message. - [JsonPropertyName("tokens")] - public long Tokens { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The heaviest individual messages in the session's context window, most-expensive first. +/// Internal filter for consuming queued system notifications. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataContextHeaviestMessagesResult +internal sealed class QueueConsumeSystemNotificationsRequest { - /// Heaviest messages, most-expensive first. - [JsonPropertyName("messages")] - public IList Messages { get => field ??= []; set; } + /// Opaque runtime-owned filter object. + [JsonPropertyName("filter")] + public JsonElement Filter { get; set; } - /// Total token count of the current context window, so callers can compute each message's share without a second call. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for the heaviest-messages query. +/// Result of enqueueing the resume-pending wake item. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataContextHeaviestMessagesRequest +internal sealed class QueueEnqueueResumePendingResult { - /// Maximum number of messages to return, most-expensive first. Omit for the server default. - [JsonPropertyName("limit")] - public long? Limit { get; set; } + /// True when a wake item was newly queued. + [JsonPropertyName("queued")] + public bool Queued { get; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionQueueEnqueueResumePendingRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Notify the session that its working directory context has changed. Emits a `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). For a local session, a report whose `cwd` diverges from the session's current working directory is ignored (the call still succeeds but records nothing and emits no event); move a local session's working directory via `metadata.setWorkingDirectory` instead. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataRecordContextChangeResult +internal sealed class SessionQueueProcessRequest { + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. +/// Cursor, batch size, and optional long-poll/filter parameters for reading session events. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionWorkingDirectoryContext +internal sealed class EventLogReadRequest { - /// Merge-base commit SHA (fork point from the remote default branch). - [JsonPropertyName("baseCommit")] - public string? BaseCommit { get; set; } - - /// Current git branch name. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Current working directory path. - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; - - /// Root directory of the git repository, resolved via git rev-parse. - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// Optional non-empty list of subagent identifiers. When provided, only events owned by one of these agents are returned; ownership recognizes the event envelope's agentId plus legacy data.agentId and data.parentToolCallId markers. This filter takes precedence over agentScope. + [JsonPropertyName("agentIds")] + public IList? AgentIds { get; set; } - /// Head commit of the current git branch. - [JsonPropertyName("headCommit")] - public string? HeadCommit { get; set; } + /// Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. + [JsonPropertyName("agentScope")] + public EventsAgentScope? AgentScope { get; set; } - /// Hosting platform type of the repository. - [JsonPropertyName("hostType")] - public SessionWorkingDirectoryContextHostType? HostType { get; set; } + /// Opaque cursor returned by a previous read. Omit on the first call to start from the beginning of the session's persisted history. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } - /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). - [JsonPropertyName("repository")] - public string? Repository { get; set; } + /// Direction to page through the session's persisted event history. 'forward' (default) pages from the cursor toward newer events (or from the start of history when no cursor is given). 'backward' enables tail-first reads: with no cursor it returns the NEWEST `max` events, and the returned cursor pages toward OLDER events on subsequent backward reads. Events within a returned batch are always in chronological (oldest-to-newest) order, even for a backward read. Backward reads cover PERSISTED history only; ephemeral events are never returned by a backward read. `direction` selects the INITIAL read only: the returned cursor is self-describing, so a continuation read pages in the cursor's own direction regardless of the `direction` passed alongside it — a forward cursor always pages forward and a backward cursor always pages backward. Pass the direction that matches the cursor to avoid confusion. + [JsonPropertyName("direction")] + public EventsReadDirection? Direction { get; set; } - /// Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com"). - [JsonPropertyName("repositoryHost")] - public string? RepositoryHost { get; set; } -} + /// When false, skip ephemeral events entirely and return only durable (persisted) events. History-backfill callers that discard ephemerals anyway should set this so the read is bounded by the durable log length instead of racing the ephemeral ring on a busy session. Defaults to true (ephemerals are interleaved with durable events in creation order). Ignored by backward reads, which always cover persisted history only. + [JsonPropertyName("includeEphemeral")] + public bool? IncludeEphemeral { get; set; } -/// Updated working-directory/git context to record on the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataRecordContextChangeRequest -{ - /// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. - [JsonPropertyName("context")] - public SessionWorkingDirectoryContext Context { get => field ??= new(); set; } + /// Maximum number of events to return in this batch (1–1000, default 200). + [JsonPropertyName("max")] + public long? Max { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Either '*' to receive all event types, or a non-empty list of event types to receive. + [JsonPropertyName("types")] + public JsonElement? Types { get; set; } + + /// Milliseconds to wait for new events when the cursor is at the tail of history. 0 (default) returns immediately even if no events are available. Capped at 30000ms. Ephemeral events that arrive during the wait are delivered in this batch but are NOT replayable on a subsequent read (use a non-zero waitMs in your next call to capture future ephemerals as they happen). This applies to forward reads only: a backward read always returns immediately and ignores `waitMs`, because backward paging covers persisted history only while new events append at the tail (the opposite end from a backward page), so no blocking or ephemeral delivery can occur. + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonPropertyName("waitMs")] + public TimeSpan? Wait { get; set; } } -/// Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for any related side-effects (file index, etc.); it does NOT change the process working directory (a session's cwd is per-session, not process-global). For local sessions the runtime validates the target first (an absolute path that exists on disk) and re-bases the permission primary directory; a rejected validation fails the call before anything is mutated, persisted, or emitted. Location-scoped permission rules are then re-keyed to the new directory (best-effort). Remote sessions only record the path. +/// Snapshot of the current tail cursor without returning any events. Use this when 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). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataSetWorkingDirectoryResult +public sealed class EventLogTailResult { - /// Working directory after the update. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; + /// Opaque cursor pointing at the current tail of the session's persisted-events history. Pass back to `read` to receive only events that arrive AFTER this snapshot. When the session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent to omitting the cursor on a first read). + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; } -/// Absolute path to set as the session's new working directory. For local sessions the path must be absolute and exist on disk: it is validated before any session state changes, and a failing validation rejects the call with nothing mutated, persisted, or emitted. Remote sessions record the path as-is. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataSetWorkingDirectoryRequest +internal sealed class SessionEventLogTailRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; } -/// Re-tokenize the session's existing messages against `modelId` and return the 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. +/// Opaque handle representing an event-type interest registration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataRecomputeContextTokensResult +public sealed class RegisterEventInterestResult { - /// Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). - [JsonPropertyName("messagesTokenCount")] - public long MessagesTokenCount { get; set; } - - /// Tokens contributed by system/developer prompt snapshots. - [JsonPropertyName("systemTokenCount")] - public long SystemTokenCount { get; set; } - - /// Sum of tokens across chat-context and system-context messages currently held by the session. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } + /// Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; } -/// Model identifier to use when re-tokenizing the session's existing messages. +/// Event type to register consumer interest for, used by runtime gating logic. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataRecomputeContextTokensRequest +internal sealed class RegisterEventInterestParams { - /// Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; + /// The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates interactive OAuth token acquisition to the consumer via `mcp.oauth_required` events; when no interest is registered the runtime still attempts non-interactive reconnect from cached or refreshable tokens, and only marks the server `needs-auth` if usable credentials are unavailable — it does not open a browser or start interactive OAuth without a consumer). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `session_limits_exhausted.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. + [JsonPropertyName("eventType")] + public string EventType { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Availability of built-in job tools surfaced to boundary consumers. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsBuiltInToolAvailabilitySnapshot +public sealed class EventLogReleaseInterestResult { - /// Whether the create-pull-request tool is available. - [JsonPropertyName("createPullRequest")] - public bool? CreatePullRequest { get; set; } - - /// Whether the report-progress tool is available. - [JsonPropertyName("reportProgress")] - public bool? ReportProgress { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Redacted job settings for a session. The job nonce is excluded. +/// Opaque handle previously returned by `registerInterest` to release. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsJobSnapshot +internal sealed class ReleaseEventInterestParams { - /// Availability of job-specific built-in tools. - [JsonPropertyName("builtInToolAvailability")] - public SessionSettingsBuiltInToolAvailabilitySnapshot? BuiltInToolAvailability { get; set; } + /// Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; - /// GitHub Actions event type for the job. - [JsonPropertyName("eventType")] - public string? EventType { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether this is the workflow's trigger job. - [JsonPropertyName("isTriggerJob")] - public bool? IsTriggerJob { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionUsageGetMetricsRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Redacted model routing settings for a session. +/// Internal absolute code-change totals reported by the owning host. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsModelSnapshot +internal sealed class SessionUsageSetCodeChangesRequest { - /// Agent service callback URL for job and progress updates. - [JsonPropertyName("callbackUrl")] - public string? CallbackUrl { get; set; } + /// Absolute changed-file count; omission preserves the previous count. + [JsonPropertyName("filesCount")] + public double? FilesCount { get; set; } - /// Default reasoning effort for the selected model. - [JsonPropertyName("defaultReasoningEffort")] - public string? DefaultReasoningEffort { get; set; } + /// Absolute added-line total, replacing the previous reading. + [JsonPropertyName("linesAdded")] + public double LinesAdded { get; set; } - /// Agent job identifier for the session. - [JsonPropertyName("instanceId")] - public string? InstanceId { get; set; } + /// Absolute removed-line total, replacing the previous reading. + [JsonPropertyName("linesRemoved")] + public double LinesRemoved { get; set; } - /// Selected model identifier. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Online-evaluation settings safe to expose across the SDK boundary. +/// Existing delegation guidance for an account without delegation access. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsOnlineEvaluationSnapshot +public sealed class SessionQuotaDelegateWarning { - /// Whether online evaluation is disabled. - [JsonPropertyName("disableOnlineEvaluation")] - public bool? DisableOnlineEvaluation { get; set; } + /// User-facing guidance. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; - /// Whether online-evaluation output-file generation is enabled. - [JsonPropertyName("enableOnlineEvaluationOutputFile")] - public bool? EnableOnlineEvaluationOutputFile { get; set; } + /// Link to upgrade the account. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// Redacted repository and GitHub host settings for a session. +/// Session quota snapshot, preserving the incumbent numeric units and reset metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsRepoSnapshot +public sealed class SessionQuotaSnapshot { - /// Checked-out repository branch. - [JsonPropertyName("branch")] - public string? Branch { get; set; } + /// Entitled quantity in this quota's units. + [JsonPropertyName("entitlementRequests")] + public double EntitlementRequests { get; set; } - /// Checked-out commit SHA. - [JsonPropertyName("commit")] - public string? Commit { get; set; } + /// Whether the provider reports available quota. + [JsonPropertyName("hasQuota")] + public bool? HasQuota { get; set; } - /// GitHub server host name. - [JsonPropertyName("host")] - public string? Host { get; set; } + /// Whether the entitlement is unlimited. + [JsonPropertyName("isUnlimitedEntitlement")] + public bool IsUnlimitedEntitlement { get; set; } - /// Protocol used to access the GitHub host. - [JsonPropertyName("hostProtocol")] - public string? HostProtocol { get; set; } + /// Additional usage in this quota's units. + [JsonPropertyName("overage")] + public double Overage { get; set; } - /// GitHub repository database ID. - [JsonPropertyName("id")] - public double? Id { get; set; } + /// Whether additional usage is allowed after quota exhaustion. + [JsonPropertyName("overageAllowedWithExhaustedQuota")] + public bool OverageAllowedWithExhaustedQuota { get; set; } - /// Repository name. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Additional-usage budget cap, when provided. + [JsonPropertyName("overageEntitlement")] + public double? OverageEntitlement { get; set; } - /// GitHub repository owner database ID. - [JsonPropertyName("ownerId")] - public double? OwnerId { get; set; } + /// Percentage of the entitlement remaining. + [JsonPropertyName("remainingPercentage")] + public double RemainingPercentage { get; set; } - /// Repository owner login. - [JsonPropertyName("ownerName")] - public string? OwnerName { get; set; } + /// Quota reset time in milliseconds since the Unix epoch, when known. + [JsonPropertyName("resetDateEpochMs")] + public double? ResetDateEpochMs { get; set; } - /// Number of commits in the pull request. - [JsonPropertyName("prCommitCount")] - public double? PrCommitCount { get; set; } + /// Whether the reset time is estimated. + [JsonPropertyName("resetDateEstimated")] + public bool? ResetDateEstimated { get; set; } - /// Whether the repository is writable. - [JsonPropertyName("readWrite")] - public bool? ReadWrite { get; set; } + /// Whether this quota uses token-based billing. + [JsonPropertyName("tokenBasedBilling")] + public bool? TokenBasedBilling { get; set; } - /// GitHub secret-scanning service URL. - [JsonPropertyName("secretScanningUrl")] - public string? SecretScanningUrl { get; set; } + /// Whether usage is allowed after quota exhaustion. + [JsonPropertyName("usageAllowedWithExhaustedQuota")] + public bool UsageAllowedWithExhaustedQuota { get; set; } - /// GitHub server base URL. - [JsonPropertyName("serverUrl")] - public string? ServerUrl { get; set; } + /// Consumed quantity in this quota's units. + [JsonPropertyName("usedRequests")] + public double UsedRequests { get; set; } } -/// Redacted validation and memory-tool settings for a session. +/// The incumbent session-owned quota and account projection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsValidationSnapshot +public sealed class SessionQuotaGetResult { - /// Whether advisory validation is enabled. - [JsonPropertyName("advisoryEnabled")] - public bool? AdvisoryEnabled { get; set; } + /// Whether the account can sign up for Copilot Free. + [JsonPropertyName("canSignupForCopilotFree")] + public bool CanSignupForCopilotFree { get; set; } - /// Whether CodeQL validation is enabled. - [JsonPropertyName("codeqlEnabled")] - public bool? CodeqlEnabled { get; set; } + /// Whether the account can delegate tasks to GitHub. + [JsonPropertyName("delegateAvailable")] + public bool DelegateAvailable { get; set; } - /// Whether code-review validation is enabled. - [JsonPropertyName("codeReviewEnabled")] - public bool? CodeReviewEnabled { get; set; } + /// Existing delegation warning for a free account. + [JsonPropertyName("delegateWarning")] + public SessionQuotaDelegateWarning? DelegateWarning { get; set; } - /// Model used for code-review validation. - [JsonPropertyName("codeReviewModel")] - public string? CodeReviewModel { get; set; } + /// Whether dynamic workflows are enabled for the active account. + [JsonPropertyName("dynamicWorkflowsEnabled")] + public bool DynamicWorkflowsEnabled { get; set; } - /// Dependabot validation timeout budget in seconds. - [JsonPropertyName("dependabotTimeout")] - public double? DependabotTimeout { get; set; } + /// Whether dynamic workflows are visible under the session's feature flags. + [JsonPropertyName("dynamicWorkflowsUiVisible")] + public bool DynamicWorkflowsUiVisible { get; set; } - /// Whether the memory-store tool is enabled. - [JsonPropertyName("memoryStoreEnabled")] - public bool? MemoryStoreEnabled { get; set; } + /// Whether the account uses the free limited Copilot plan. + [JsonPropertyName("isFreeUser")] + public bool IsFreeUser { get; set; } - /// Whether the memory-vote tool is enabled. - [JsonPropertyName("memoryVoteEnabled")] - public bool? MemoryVoteEnabled { get; set; } + /// Whether the account uses token-based billing. + [JsonPropertyName("isTbbUser")] + public bool IsTbbUser { get; set; } - /// Whether secret-scanning validation is enabled. - [JsonPropertyName("secretScanningEnabled")] - public bool? SecretScanningEnabled { get; set; } + /// Whether model cost columns should be shown. + [JsonPropertyName("modelCostColumnVisible")] + public bool ModelCostColumnVisible { get; set; } - /// General validation timeout budget in seconds. - [JsonPropertyName("timeout")] - public double? Timeout { get; set; } + /// Resolved Copilot plan tier. + [JsonPropertyName("planTier")] + public SessionQuotaPlanTier PlanTier { get; set; } + + /// Whether premium-request costs are billable. + [JsonPropertyName("premiumRequestsBillable")] + public bool PremiumRequestsBillable { get; set; } + + /// Provider-owned account quota state, including snapshots without numeric balances. + [JsonPropertyName("providerQuotas")] + public IList? ProviderQuotas { get; set; } + + /// Known quota snapshots, keyed by the provider's quota type. + [JsonPropertyName("snapshots")] + public IDictionary Snapshots { get => field ??= new Dictionary(); set; } + + /// Upgrade link for a free account. + [JsonPropertyName("upgradeUrl")] + public string? UpgradeUrl { get; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionQuotaGetRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded. +/// The incumbent session-owned quota and account projection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsSnapshot +public sealed class SessionQuotaRefreshResult { - /// Name of the SDK client that created the session. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Whether the account can sign up for Copilot Free. + [JsonPropertyName("canSignupForCopilotFree")] + public bool CanSignupForCopilotFree { get; set; } - /// Redacted job settings. - [JsonPropertyName("job")] - public SessionSettingsJobSnapshot Job { get => field ??= new(); set; } + /// Whether the account can delegate tasks to GitHub. + [JsonPropertyName("delegateAvailable")] + public bool DelegateAvailable { get; set; } - /// Redacted model routing settings. - [JsonPropertyName("model")] - public SessionSettingsModelSnapshot Model { get => field ??= new(); set; } + /// Existing delegation warning for a free account. + [JsonPropertyName("delegateWarning")] + public SessionQuotaDelegateWarning? DelegateWarning { get; set; } - /// Online-evaluation settings safe for SDK consumers. - [JsonPropertyName("onlineEvaluation")] - public SessionSettingsOnlineEvaluationSnapshot OnlineEvaluation { get => field ??= new(); set; } + /// Whether dynamic workflows are enabled for the active account. + [JsonPropertyName("dynamicWorkflowsEnabled")] + public bool DynamicWorkflowsEnabled { get; set; } - /// Redacted repository and host settings. - [JsonPropertyName("repo")] - public SessionSettingsRepoSnapshot Repo { get => field ??= new(); set; } + /// Whether dynamic workflows are visible under the session's feature flags. + [JsonPropertyName("dynamicWorkflowsUiVisible")] + public bool DynamicWorkflowsUiVisible { get; set; } - /// Session start time as Unix epoch milliseconds. - [JsonPropertyName("startTimeMs")] - public double? StartTimeMs { get; set; } + /// Whether the account uses the free limited Copilot plan. + [JsonPropertyName("isFreeUser")] + public bool IsFreeUser { get; set; } - /// Session timeout in milliseconds. - [JsonPropertyName("timeoutMs")] - public double? TimeoutMs { get; set; } + /// Whether the account uses token-based billing. + [JsonPropertyName("isTbbUser")] + public bool IsTbbUser { get; set; } - /// Redacted validation and memory-tool settings. - [JsonPropertyName("validation")] - public SessionSettingsValidationSnapshot Validation { get => field ??= new(); set; } + /// Whether model cost columns should be shown. + [JsonPropertyName("modelCostColumnVisible")] + public bool ModelCostColumnVisible { get; set; } - /// Agent runtime version selector copied from the session settings, such as `latest` or a runtime release identifier. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Resolved Copilot plan tier. + [JsonPropertyName("planTier")] + public SessionQuotaPlanTier PlanTier { get; set; } + + /// Whether premium-request costs are billable. + [JsonPropertyName("premiumRequestsBillable")] + public bool PremiumRequestsBillable { get; set; } + + /// Provider-owned account quota state, including snapshots without numeric balances. + [JsonPropertyName("providerQuotas")] + public IList? ProviderQuotas { get; set; } + + /// Known quota snapshots, keyed by the provider's quota type. + [JsonPropertyName("snapshots")] + public IDictionary Snapshots { get => field ??= new Dictionary(); set; } + + /// Upgrade link for a free account. + [JsonPropertyName("upgradeUrl")] + public string? UpgradeUrl { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsSnapshotRequest +internal sealed class SessionQuotaRefreshRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of evaluating a Rust-owned settings predicate. +/// A pending session quota warning, consumed once by takeWarnings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsEvaluatePredicateResult +public sealed class QuotaWarningProjection { - /// Whether the named settings predicate evaluated to enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// User-facing warning text. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Related account or upgrade link. + [JsonPropertyName("url")] + public string? Url { get; set; } + + /// Existing warning category. + [JsonPropertyName("warningType")] + public string WarningType { get; set; } = string.Empty; } -/// Named Rust-owned settings predicate to evaluate for this session. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsEvaluatePredicateRequest +internal sealed class SessionQuotaTakeWarningsRequest { - /// Predicate name. The runtime owns the raw feature-flag names and composition logic. - [JsonPropertyName("name")] - public SessionSettingsPredicateName Name { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Tool name for tool-scoped predicates such as trivial-change handling. - [JsonPropertyName("toolName")] - public string? ToolName { get; set; } } -/// Content-exclusion decision for one requested path. +/// Prediction result. Available results include prediction details; unavailable results include an explicit reason. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ContentExclusionPathCheck +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SessionLimitPredictionResultAvailable), "available")] +[JsonDerivedType(typeof(SessionLimitPredictionResultUnavailable), "unavailable")] +public partial class SessionLimitPredictionResult { - /// Whether the session's complete content-exclusion policy excludes the path. - [JsonPropertyName("excluded")] - public bool Excluded { get; set; } - - /// The path supplied by the caller. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Batch content-exclusion result. Callers must fail closed when policy evaluation is unavailable. + +/// Baseline data provenance for a prediction. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ContentExclusionCheckPathsResult +public sealed class SessionLimitPredictionBaselineData { - /// Whether the session's policy service was available for the complete batch. When false, checks is empty and callers must treat every requested path as excluded. - [JsonPropertyName("available")] - public bool Available { get; set; } + /// End of the baseline data slice. + [JsonPropertyName("windowEnd")] + public string WindowEnd { get; set; } = string.Empty; - /// Per-path decisions in request order. Empty when available is false. - [JsonPropertyName("checks")] - public IList Checks { get => field ??= []; set; } + /// Start of the baseline data slice. + [JsonPropertyName("windowStart")] + public string WindowStart { get; set; } = string.Empty; } -/// Local file system absolute paths within the session working directory to check against its content-exclusion policy. +/// Semantic usage tier and its AI-credit cap. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ContentExclusionCheckPathsRequest +public sealed class SessionLimitPredictionTierOption { - /// Local file system absolute paths within the session working directory to check. Results are returned in the same order, including duplicates. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// AI-credit cap for this tier. + [JsonPropertyName("cap")] + public double Cap { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Semantic usage tier. + [JsonPropertyName("tier")] + public SessionLimitPredictionTier Tier { get; set; } } -/// Identifier of the spawned shell process, usable with shell.kill while the process is running. +/// Explainable AI-credit session-limit prediction. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellExecResult +public sealed class SessionLimitPredictionDetails { - /// Identifier usable with shell.kill while the process is running. - [JsonPropertyName("processId")] - public string ProcessId { get; set; } = string.Empty; -} + /// Baseline data provenance. + [JsonPropertyName("baselineData")] + public SessionLimitPredictionBaselineData BaselineData { get => field ??= new(); set; } -/// Shell command to run, with optional working directory and timeout in milliseconds. Spawn failures return an RPC error. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellExecRequest -{ - /// Shell command to execute. - [JsonPropertyName("command")] - public string Command { get; set; } = string.Empty; + /// Client population used for the prediction. + [JsonPropertyName("clientType")] + public SessionLimitPredictionClientType ClientType { get; set; } - /// Working directory (defaults to session working directory). - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Resolved model family when known. + [JsonPropertyName("family")] + public string? Family { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Model identifier used for lookup. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; - /// Timeout in milliseconds (default: 30000). - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("timeout")] - public TimeSpan? Timeout { get; set; } + /// Recommended maximum AI credits for this session. + [JsonPropertyName("recommendedCap")] + public double RecommendedCap { get; set; } + + /// Tier chosen as the recommended cap. + [JsonPropertyName("recommendedTier")] + public SessionLimitPredictionTier RecommendedTier { get; set; } + + /// Baseline fallback level used to create the prediction. + [JsonPropertyName("source")] + public SessionLimitPredictionSource Source { get; set; } + + /// Key matched at the source level, such as a model id, family id, or `global`. + [JsonPropertyName("sourceKey")] + public string SourceKey { get; set; } = string.Empty; + + /// Ordered usage tiers and their AI-credit caps. + [JsonPropertyName("tiers")] + public IList Tiers { get => field ??= []; set; } } -/// Indicates whether the signal was delivered; false if the process was unknown or already exited. +/// The available variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellKillResult +public partial class SessionLimitPredictionResultAvailable : SessionLimitPredictionResult { - /// Whether the signal was sent successfully. - [JsonPropertyName("killed")] - public bool Killed { get; set; } + /// + [JsonIgnore] + public override string Kind => "available"; + + /// Predicted session limit details. + [JsonPropertyName("prediction")] + public required SessionLimitPredictionDetails Prediction { get; set; } } -/// Identifier of a process previously returned by "shell.exec" and the signal to send. +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellKillRequest +public partial class SessionLimitPredictionResultUnavailable : SessionLimitPredictionResult { - /// Process identifier returned by shell.exec. - [JsonPropertyName("processId")] - public string ProcessId { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "unavailable"; - /// Signal to send (default: SIGTERM). - [JsonPropertyName("signal")] - public ShellKillSignal? Signal { get; set; } + /// Reason no prediction is available. + [JsonPropertyName("reason")] + public required SessionLimitPredictionUnavailableReason Reason { get; set; } } -/// Result of a user-requested shell command. +/// RPC data type for SessionLimitPredictionPredict operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserRequestedShellCommandResult +public sealed class SessionLimitPredictionPredictRequest { - /// Error output when the execution failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Process exit code, when available. - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } - - /// Captured command output. - [JsonPropertyName("output")] - public string Output { get; set; } = string.Empty; - - /// Whether the command completed successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Client type to size for. Defaults to `cli-interactive`. + [JsonPropertyName("clientType")] + public SessionLimitPredictionClientType? ClientType { get; set; } - /// Tool call id emitted for the shell execution. - [JsonPropertyName("toolCallId")] - public string ToolCallId { get; set; } = string.Empty; + /// Optional model identifier override. If omitted, the session's current model is used. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } } -/// User-requested shell command and cancellation handle. +/// RPC data type for SessionLimitPredictionPredictRequestWithSession operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellExecuteUserRequestedRequest +internal sealed class SessionLimitPredictionPredictRequestWithSession { - /// Shell command to execute. - [JsonPropertyName("command")] - public string Command { get; set; } = string.Empty; + /// Client type to size for. Defaults to `cli-interactive`. + [JsonPropertyName("clientType")] + public SessionLimitPredictionClientType? ClientType { get; set; } - /// Caller-provided cancellation handle for this execution. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Optional model identifier override. If omitted, the session's current model is used. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Cancellation result for a user-requested shell command. +/// GitHub URL for the session and a flag indicating whether remote steering is enabled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CancelUserRequestedShellCommandResult +public sealed class RemoteEnableResult { - /// Whether an in-flight execution was found and signalled to cancel. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } + /// Whether remote steering is enabled. + [JsonPropertyName("remoteSteerable")] + public bool RemoteSteerable { get; set; } + + /// GitHub frontend URL for this session. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// User-requested shell execution cancellation handle. +/// Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellCancelUserRequestedRequest +internal sealed class RemoteEnableRequest { - /// Request ID previously passed to executeUserRequested. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. + [JsonPropertyName("mode")] + public RemoteSessionMode? Mode { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Post-compaction context window usage breakdown. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryCompactContextWindow +internal sealed class SessionRemoteDisableRequest { - /// Token count from non-system messages (user, assistant, tool). - [JsonPropertyName("conversationTokens")] - public long? ConversationTokens { get; set; } - - /// Current total tokens in the context window (system + conversation + tool definitions). - [JsonPropertyName("currentTokens")] - public long CurrentTokens { get; set; } - - /// Current number of messages in the conversation. - [JsonPropertyName("messagesLength")] - public long MessagesLength { get; set; } - - /// Token count from system message(s). - [JsonPropertyName("systemTokens")] - public long? SystemTokens { get; set; } - - /// Maximum token count for the model's context window. - [JsonPropertyName("tokenLimit")] - public long TokenLimit { get; set; } - - /// Token count from tool definitions. - [JsonPropertyName("toolDefinitionsTokens")] - public long? ToolDefinitionsTokens { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. +/// 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. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryCompactResult +public sealed class RemoteNotifySteerableChangedResult { - /// Post-compaction context window usage breakdown. - [JsonPropertyName("contextWindow")] - public HistoryCompactContextWindow? ContextWindow { get; set; } - - /// Number of messages removed during compaction. - [JsonPropertyName("messagesRemoved")] - public long MessagesRemoved { get; set; } - - /// Whether compaction completed successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } +} - /// Summary text produced by compaction. Omitted when compaction did not produce a summary (e.g. failure path). - [JsonPropertyName("summaryContent")] - public string? SummaryContent { get; set; } +/// New remote-steerability state to persist as a `session.remote_steerable_changed` event. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RemoteNotifySteerableChangedRequest +{ + /// Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. + [JsonPropertyName("remoteSteerable")] + public bool RemoteSteerable { get; set; } - /// Number of tokens freed by compaction. - [JsonPropertyName("tokensRemoved")] - public long TokensRemoved { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// RPC data type for SessionHistoryCompact operations. +/// Current sharing status and shareable GitHub URL for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionHistoryCompactRequest +public sealed class VisibilityGetResult { - /// Optional user-provided instructions to focus the compaction summary. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(4000)] - [JsonPropertyName("customInstructions")] - public string? CustomInstructions { get; set; } + /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("shareUrl")] + public string? ShareUrl { get; set; } - /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. - [JsonPropertyName("tokenLimit")] - public long? TokenLimit { get; set; } + /// Current sharing status. Absent when the session is not synced or the status could not be retrieved (e.g. the user is not authenticated). + [JsonPropertyName("status")] + public SessionVisibilityStatus? Status { get; set; } - /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). - [JsonPropertyName("trigger")] - public SessionHistoryCompactRequestTrigger? Trigger { get; set; } + /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the session cannot be shared and `status`/`shareUrl` are absent. + [JsonPropertyName("synced")] + public bool Synced { get; set; } } -/// RPC data type for SessionHistoryCompactRequestWithSession operations. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryCompactRequestWithSession +internal sealed class SessionVisibilityGetRequest { - /// Optional user-provided instructions to focus the compaction summary. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(4000)] - [JsonPropertyName("customInstructions")] - public string? CustomInstructions { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. - [JsonPropertyName("tokenLimit")] - public long? TokenLimit { get; set; } - - /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). - [JsonPropertyName("trigger")] - public SessionHistoryCompactRequestTrigger? Trigger { get; set; } } -/// Number of events that were removed by the truncation. +/// Effective sharing status and shareable GitHub URL after updating session visibility. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryTruncateResult +public sealed class VisibilitySetResult { - /// Failure detail when checkpointCleanupFailed is true. - [JsonPropertyName("checkpointCleanupError")] - public string? CheckpointCleanupError { get; set; } + /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("shareUrl")] + public string? ShareUrl { get; set; } - /// True when conversation truncation succeeded but post-truncation workspace checkpoint cleanup failed. History is already truncated; callers may still prune snapshots but should report a checkpoint-cleanup rather than a truncation failure. - [JsonPropertyName("checkpointCleanupFailed")] - public bool? CheckpointCleanupFailed { get; set; } + /// Effective sharing status after the update. May differ from the requested status for task types that are already visible to repository readers by default. Absent when the update could not be applied (e.g. the session is not synced or the user is not authenticated). + [JsonPropertyName("status")] + public SessionVisibilityStatus? Status { get; set; } - /// Number of events that were removed. - [JsonPropertyName("eventsRemoved")] - public long EventsRemoved { get; set; } + /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the visibility change could not be applied and `status`/`shareUrl` are absent. + [JsonPropertyName("synced")] + public bool Synced { get; set; } } -/// Identifier of the event to truncate to; this event and all later events are removed. +/// Desired sharing status for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryTruncateRequest +internal sealed class VisibilitySetRequest { - /// Event ID to truncate to. This event and all events after it are removed from the session. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Sharing status to apply. "repo" makes the session visible to repository readers; "unshared" restricts it to the creator and collaborators. + [JsonPropertyName("status")] + public SessionVisibilityStatus Status { get; set; } } -/// A root user turn that the session can rewind to. +/// Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text, recurrence, and next run time. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryRewindPoint +public sealed class ScheduleEntry { - /// Whether at least one file in this turn or a later turn can be restored. - [JsonPropertyName("canRestoreFiles")] - public bool CanRestoreFiles { get; set; } + /// Absolute fire time (epoch milliseconds) for a one-shot calendar schedule. + [JsonPropertyName("at")] + public long? At { get; set; } - /// ID of the user.message event that begins the discarded suffix. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; + /// 5-field cron expression for a recurring calendar schedule, evaluated in `tz`. + [JsonPropertyName("cron")] + public string? Cron { get; set; } - /// Number of unique files in this turn and all later turns that have captured changes. - [JsonPropertyName("fileCount")] - public long FileCount { get; set; } + /// Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// Whether this turn was an automatically injected autopilot continuation. - [JsonPropertyName("isAutopilotContinuation")] - public bool IsAutopilotContinuation { get; set; } + /// Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). + [JsonPropertyName("id")] + public long Id { get; set; } - /// Lines added by this turn's captured file changes. - [JsonPropertyName("linesAdded")] - public long LinesAdded { get; set; } + /// Interval between scheduled ticks, in milliseconds (relative-interval schedules). + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonPropertyName("intervalMs")] + public TimeSpan? Interval { get; set; } - /// Lines removed by this turn's captured file changes. - [JsonPropertyName("linesRemoved")] - public long LinesRemoved { get; set; } + /// ISO 8601 timestamp when the next tick is scheduled to fire. + [JsonPropertyName("nextRunAt")] + public DateTimeOffset NextRunAt { get; set; } - /// ISO timestamp of the user turn. - [JsonPropertyName("timestamp")] - public string Timestamp { get; set; } = string.Empty; + /// Prompt text that gets enqueued on every tick. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Whether this turn itself captured any file changes. - [JsonPropertyName("turnChangedFiles")] - public bool TurnChangedFiles { get; set; } + /// Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). + [JsonPropertyName("recurring")] + public bool Recurring { get; set; } - /// User-visible message text for the turn. - [JsonPropertyName("userMessage")] - public string UserMessage { get; set; } = string.Empty; + /// True for a self-paced (`dynamic`) schedule: no fixed cadence; the model arms each next run via the `manage_schedule` `wakeup` action. `nextRunAt` is model-controlled. + [JsonPropertyName("selfPaced")] + public bool? SelfPaced { get; set; } + + /// IANA timezone the `cron` expression is evaluated in. + [JsonPropertyName("tz")] + public string? Tz { get; set; } } -/// Rewind points and file-change-tracking availability for the session. +/// Snapshot of the currently active recurring prompts for this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryListRewindPointsResult +public sealed class ScheduleList { - /// Whether this session captured file changes from its first turn. - [JsonPropertyName("fileChangeTrackingEnabled")] - public bool FileChangeTrackingEnabled { get; set; } + /// Active scheduled prompts, ordered by id. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } +} - /// Root user turns in chronological order. Empty when `unavailableReason` is set. - [JsonPropertyName("points")] - public IList Points { get => field ??= []; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionScheduleListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Why the listed points could not be produced, when applicable; the points list is empty whenever it is set. `unsupported-remote-session` is permanent for the session and comes with `fileChangeTrackingEnabled: false`. `session-busy` is transient and only ever reported by a session that *is* tracking (`fileChangeTrackingEnabled: true`), because the file-change captures cannot be read while work that may still mutate them is in flight; the same request succeeds once the session settles, so a client that wants points should retry rather than treat it as a failure. It is never `file-change-tracking-disabled`: an untracked local session still lists conversation-only points and reports that through `fileChangeTrackingEnabled: false`. - [JsonPropertyName("unavailableReason")] - public HistoryRewindUnavailableReason? UnavailableReason { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionScheduleHydrateRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Whether the session currently has an active self-paced schedule. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ScheduleHasSelfPacedResult +{ + /// True when at least one active schedule is self-paced. + [JsonPropertyName("hasSelfPaced")] + public bool HasSelfPaced { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryListRewindPointsRequest +internal sealed class SessionScheduleHasSelfPacedRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A file that a conversation-and-files rewind would restore. +/// Result of registering or re-arming a scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryRewindFilePreview +internal sealed class ScheduleAddResult { - /// Aggregate change made across the discarded turns. - [JsonPropertyName("changeType")] - public HistoryRewindChangeType ChangeType { get; set; } - - /// Lines added across the discarded turns. - [JsonPropertyName("linesAdded")] - public long LinesAdded { get; set; } - - /// Lines removed across the discarded turns. - [JsonPropertyName("linesRemoved")] - public long LinesRemoved { get; set; } + /// The registered or updated schedule entry. + [JsonPropertyName("entry")] + public ScheduleEntry? Entry { get; set; } - /// Absolute path of the captured file. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// User-facing validation error, when registration failed. + [JsonPropertyName("error")] + public string? Error { get; set; } } -/// Files and aggregate changes for a prospective rewind. +/// Register a relative-interval scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryPreviewRewindResult +internal sealed class ScheduleAddRequest { - /// Whether file restore is available for this session. This is authoritative: switch on it and read `reason` only when it is false. - [JsonPropertyName("available")] - public bool Available { get; set; } - - /// Number of unique files in the preview. - [JsonPropertyName("fileCount")] - public long FileCount { get; set; } + /// Optional display-only prompt label. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// Files ordered by path. - [JsonPropertyName("files")] - public IList Files { get => field ??= []; set; } + /// Human-readable interval such as `30s`, `5m`, or `2h`. + [JsonPropertyName("interval")] + public string Interval { get; set; } = string.Empty; - /// Why file restore is unavailable, when applicable. Populated only when `available` is false and never set when `available` is true. - [JsonPropertyName("reason")] - public HistoryRewindUnavailableReason? Reason { get; set; } -} + /// Prompt text to enqueue when the schedule fires. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; -/// Event boundary to preview for conversation-and-files rewind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryPreviewRewindRequest -{ - /// ID of the user.message event that begins the discarded suffix. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; + /// Whether the schedule should re-arm after each tick. Defaults to true. + [JsonPropertyName("recurring")] + public bool? Recurring { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A captured file that rewind intentionally left unchanged. +/// Register a cron scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistorySkippedFileRestore +internal sealed class ScheduleAddCronRequest { - /// Absolute path of the skipped file. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Reason the file was not restored. - [JsonPropertyName("reason")] - public HistoryFileRestoreSkipReason Reason { get; set; } -} + /// 5-field cron expression. + [JsonPropertyName("cron")] + public string Cron { get; set; } = string.Empty; -/// Structured outcome of a rewind request. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryRewindResult -{ - /// Failure detail. Set only for the failure and partial-failure outcomes (`files-rolled-back`, `rollback-incomplete`, `truncation-failed`, `checkpoint-cleanup-failed`, `snapshot-prune-failed`); omitted for `success` and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`). - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Optional display-only prompt label. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// Number of persisted events removed by conversation truncation. Present only when truncation succeeded (outcomes `success`, `checkpoint-cleanup-failed`, and `snapshot-prune-failed`); omitted for every unavailable outcome (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`) and for `truncation-failed`, `files-rolled-back`, and `rollback-incomplete`. - [JsonPropertyName("eventsRemoved")] - public long? EventsRemoved { get; set; } + /// Prompt text to enqueue when the schedule fires. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Overall rewind outcome. This discriminates the result: it governs which of the remaining fields are populated, so consumers must switch on it before reading `eventsRemoved`, `restoredFiles`, `skippedFiles`, or `error`. See each field for the outcomes that populate it. - [JsonPropertyName("outcome")] - public HistoryRewindOutcome Outcome { get; set; } + /// Whether the schedule should re-arm after each tick. Defaults to true. + [JsonPropertyName("recurring")] + public bool? Recurring { get; set; } - /// Absolute paths restored to their captured preimages. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. - [JsonPropertyName("restoredFiles")] - public IList RestoredFiles { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Captured files intentionally left unchanged. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. - [JsonPropertyName("skippedFiles")] - public IList SkippedFiles { get => field ??= []; set; } + /// IANA timezone for evaluating the cron expression. + [JsonPropertyName("tz")] + public string? Tz { get; set; } } -/// Boundary and mode for rewinding session history. +/// Register an absolute-time scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryRewindRequest +internal sealed class ScheduleAddAtRequest { - /// ID of the user.message event that begins the discarded suffix. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; + /// Epoch milliseconds when the prompt should fire. + [JsonPropertyName("at")] + public long At { get; set; } - /// Whether to rewind only conversation history or also restore captured files. - [JsonPropertyName("mode")] - public HistoryRewindMode Mode { get; set; } + /// Optional display-only prompt label. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } + + /// Prompt text to enqueue when the schedule fires. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; + + /// Whether the schedule should re-arm after each tick. Defaults to false. + [JsonPropertyName("recurring")] + public bool? Recurring { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether an in-progress background compaction was cancelled. +/// Register a self-paced scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryCancelBackgroundCompactionResult +internal sealed class ScheduleAddSelfPacedRequest { - /// Whether an in-progress background compaction was cancelled. False when no compaction was running, when the session is remote, or when the underlying processor was unavailable. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } -} + /// Optional display-only prompt label. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } + + /// Prompt text to enqueue when the schedule fires. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryCancelBackgroundCompactionRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether an in-progress manual compaction was aborted. +/// Re-arm a self-paced scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryAbortManualCompactionResult +internal sealed class ScheduleRearmSelfPacedRequest { - /// Whether an in-progress manual compaction was aborted. False when no manual compaction was running, when its abort controller was already aborted, or when the session is remote. - [JsonPropertyName("aborted")] - public bool Aborted { get; set; } -} + /// Epoch milliseconds when the prompt should next fire. + [JsonPropertyName("at")] + public long At { get; set; } + + /// Id of the self-paced scheduled prompt. + [JsonPropertyName("id")] + public long Id { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryAbortManualCompactionRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Markdown summary of the conversation context (empty when not available). +/// Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistorySummarizeForHandoffResult +public sealed class ScheduleStopResult { - /// Markdown summary of the conversation context produced by an LLM. Empty string when there are no messages or when the session does not support local summarization. - [JsonPropertyName("summary")] - public string Summary { get; set; } = string.Empty; + /// The removed entry, or omitted if no entry matched. + [JsonPropertyName("entry")] + public ScheduleEntry? Entry { get; set; } } -/// Identifies the target session. +/// Identifier of the scheduled prompt to remove. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistorySummarizeForHandoffRequest +internal sealed class ScheduleStopRequest { + /// Id of the scheduled prompt to remove. + [JsonPropertyName("id")] + public long Id { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// What a successful clear removed. A clear that could not be applied rejects instead of reporting a count. +/// A bearer token supplied by the SDK client for a BYOK provider. The runtime sets it as `Authorization: Bearer <token>` on the outbound request and does no caching; the SDK consumer owns token caching and refresh. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryClearContextResult +public sealed class ProviderTokenAcquireResult { - /// Number of non-system, non-developer messages that were removed from the conversation. Zero only when the window already held no conversation. - [JsonPropertyName("messagesCleared")] - public long MessagesCleared { get; set; } + /// The bearer token value (without the `Bearer ` prefix). + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// Parameters for clearing the conversation and seeding the window that replaces it. +/// Asks the SDK client to acquire a bearer token for a BYOK provider whose config set `hasBearerTokenProvider: true`. Issued by the runtime before each outbound model request; the runtime does no caching, so this is sent once per request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryClearContextRequest +public sealed class ProviderTokenAcquireRequest { - /// First user message of the fresh context window. Required: a cleared window holding only system and developer messages is not a conversation a model can answer, so every clear seeds the window it creates. Delivered by the enclosing turn driver once the agentic loop exits, which is why the call must be made from inside a tool handler. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Name of the BYOK provider needing a token. For the legacy whole-session provider this is the implicit provider name; for named providers it is the configured provider name. + [JsonPropertyName("providerName")] + public string ProviderName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// User-facing pending queue entry, with kind and display text for a queued message, slash command, or model change. +/// Result returned by an extension workflow closure. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueuePendingItems +public sealed class WorkflowExecuteResult { - /// Agent mode stored on this queued entry, as stamped when it was enqueued. Items without an explicit mode report interactive. This is not necessarily the mode that will constrain the turn: a plan or autopilot session applies its own write gate, continuation loop and permission posture to every drained item regardless of the mode stored here. - [JsonPropertyName("agentMode")] - public SendAgentMode AgentMode { get; set; } - - /// Human-readable text to display for this queue entry in the UI. - [JsonPropertyName("displayText")] - public string DisplayText { get; set; } = string.Empty; - - /// Stable opaque id for the canonical queued item. Batch rows share one id. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Whether this item is a queued user message or a queued slash command / model change. - [JsonPropertyName("kind")] - public QueuePendingItemsKind Kind { get; set; } - - /// Stable identity of the queued user message. Present for message rows and absent for slash commands and model changes. - [JsonPropertyName("messageId")] - public string? MessageId { get; set; } - - /// Optional source tag associated with this pending queue entry. This is an open string, not authenticated authorship. In particular, `user` does not prove that a person typed the message. If the source is absent or unrecognized, consumers must not infer human or agent authorship and should handle the entry neutrally. Consumers should tolerate future source values. - [JsonPropertyName("source")] - public string? Source { get; set; } + /// Workflow result value. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } } -/// Snapshot of the session's pending queued items and immediate-steering messages. +/// Parameters sent to the owning extension to execute a workflow closure. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueuePendingItemsResult +public sealed class WorkflowExecuteRequest { - /// How many leading entries of `steeringMessages` have already been folded into the running turn (and so have an emitted `user.message`), as opposed to still waiting for one. Absent for hosts that do not distinguish the two. - [JsonPropertyName("inFlightSteeringCount")] - public long? InFlightSteeringCount { get; set; } + /// Workflow input value. + [JsonPropertyName("args")] + public JsonElement Args { get; set; } - /// Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } + /// Opaque token identifying this workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// Display text for messages currently in the immediate steering queue (interjections sent during a running turn). - [JsonPropertyName("steeringMessages")] - public IList SteeringMessages { get => field ??= []; set; } + /// Registered workflow name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// ID of the running turn's user message while the model has not answered it, so `withdrawMessage` can still take it back once nothing sent after it is pending. A message leaves `items` when its turn starts, before its `user.message` is recorded; this tells that message apart from one that was removed. Absent when no turn prompt can be taken back. - [JsonPropertyName("withdrawableTurnMessageId")] - public string? WithdrawableTurnMessageId { get; set; } -} + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueuePendingItemsRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Internal snapshot of native queue state for local session orchestration. +/// Parameters for cooperatively aborting a workflow body. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueSnapshotResult +public sealed class WorkflowAbortRequest { - /// Queue item identifier of a model switch that has been dequeued but not yet applied. - [JsonPropertyName("inFlightModelChangeId")] - public string? InFlightModelChangeId { get; set; } - - /// Insertion orders for queued items, aligned with `items`. - [JsonPropertyName("itemOrders")] - public IList? ItemOrders { get; set; } - - /// User-facing pending items in FIFO order. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } - - /// Insertion orders for immediate steering messages, aligned with `steeringMessages`. - [JsonPropertyName("steeringMessageOrders")] - public IList? SteeringMessageOrders { get; set; } + /// Opaque token identifying the execution attempt to abort. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// Immediate steering messages waiting for an active turn. - [JsonPropertyName("steeringMessages")] - public IList SteeringMessages { get => field ??= []; set; } -} + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueSnapshotRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of moving a queued item. +/// Whether the client authoritatively confirmed its external work stopped. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueMoveItemResult +public sealed class ClientTaskCancelResult { - /// True when the item changed position; false when it was already at the requested position. - [JsonPropertyName("changed")] - public bool Changed { get; set; } + /// True only when the owner confirms that external work stopped before responding. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } } -/// Parameters for moving a queued item by stable id. +/// Runtime-to-owner cancellation request for a client-owned task. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueMoveItemRequest +public sealed class ClientTaskCancelRequest { - /// Stable opaque queued-item id. + /// Opaque identifier shared by coalesced cancellation callers. + [JsonPropertyName("cancellationId")] + public string CancellationId { get; set; } = string.Empty; + + /// Owner-scoped task key included for correlation. + [JsonPropertyName("clientTaskId")] + public string ClientTaskId { get; set; } = string.Empty; + + /// Canonical runtime-generated task identifier. [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; - /// Target session identifier. + /// Reason the runtime requests cancellation. + [JsonPropertyName("reason")] + public ClientTaskCancelReason Reason { get; set; } + + /// Session that owns the client task. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Zero-based target position in the public visible queue. Values outside the queue clamp to an end. - [JsonPropertyName("toPosition")] - public long ToPosition { get; set; } } -/// Result of inserting a queued message. +/// Describes a filesystem error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueInsertAtResult +public sealed class SessionFsError { - /// Fresh stable opaque id assigned to the inserted item. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Error classification. + [JsonPropertyName("code")] + public SessionFsErrorCode Code { get; set; } + + /// Free-form detail about the error, for logging/diagnostics. + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// For failed writeFile requests only: true if the provider changed the target before failing. Omit when unknown or unchanged. + [JsonPropertyName("writeChanged")] + public bool? WriteChanged { get; set; } } -/// Serializable message fields accepted by queue.insertAt. +/// File content as a UTF-8 string, or a filesystem error if the read failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueInsertMessage +public sealed class SessionFsReadFileResult { - /// Optional explicit agent mode. When omitted, the session's current mode is assigned. - [JsonPropertyName("agentMode")] - public SendAgentMode? AgentMode { get; set; } - - /// Optional attachments for the message. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } - - /// Whether the message is billable. - [JsonPropertyName("billable")] - public bool? Billable { get; set; } - - /// Accepted for internal SendOptions compatibility but ignored; delivery is derived from current session activity. - [JsonPropertyName("delivery")] - public string? Delivery { get; set; } - - /// Optional user-facing display text. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } - - /// Accepted for SendOptions compatibility but ignored; inserted items always use queued delivery semantics. - [JsonPropertyName("mode")] - public SendMode? Mode { get; set; } - - /// Accepted for SendOptions compatibility but ignored; the requested public position controls placement. - [JsonPropertyName("prepend")] - public bool? Prepend { get; set; } + /// File content as UTF-8 string. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// The user message text. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } +} - /// Per-turn request headers. - [JsonPropertyName("requestHeaders")] - public IDictionary? RequestHeaders { get; set; } +/// Path of the file to read from the client-provided session filesystem. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionFsReadFileRequest +{ + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Required tool name for the turn, when any. - [JsonPropertyName("requiredTool")] - public string? RequiredTool { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Optional provenance source. `system` is rejected: it would hide the inserted row from `pendingItems` and make it unaddressable while still executing, so inserted items must stay visible. - [JsonPropertyName("source")] - public string? Source { get; set; } +/// File bytes as standard base64, or a filesystem error if the read failed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionFsReadFileBytesResult +{ + /// Exact file bytes encoded as standard base64. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Accepted for SendOptions compatibility but ignored; insertion scheduling is controlled by the queue drain state. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } -/// Parameters for inserting a queued message at a public visible position. +/// Path of the binary file to read from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueInsertAtRequest +public sealed class SessionFsReadFileBytesRequest { - /// Queued message contents and delivery metadata. - [JsonPropertyName("message")] - public QueueInsertMessage Message { get => field ??= new(); set; } - - /// Zero-based position in the public visible queue. Values outside the queue clamp to an end. - [JsonPropertyName("position")] - public long Position { get; set; } + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of removing a queued item. +/// File path, content to write, and optional mode for the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueRemoveAtResult +public sealed class SessionFsWriteFileRequest { - /// True when the addressed item was removed. - [JsonPropertyName("removed")] - public bool Removed { get; set; } -} + /// Content to write. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; -/// Parameters for removing a queued item by stable id. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueRemoveAtRequest -{ - /// Stable opaque ID of the queued item to remove. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Optional POSIX-style mode for newly created files. + [JsonPropertyName("mode")] + public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of editing a queued message. +/// File path, standard-base64-encoded bytes to write, and optional mode for the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueUpdateTextResult +public sealed class SessionFsWriteFileBytesRequest { - /// True when the stored text changed. - [JsonPropertyName("updated")] - public bool Updated { get; set; } + /// Exact file bytes encoded as standard base64. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Optional POSIX-style mode for newly created files. + [JsonPropertyName("mode")] + public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for editing a single queued message. +/// File path, content to append, and optional mode for the client-provided session filesystem. Implementations create parent directories as needed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueUpdateTextRequest +public sealed class SessionFsAppendFileRequest { - /// Optional replacement prompt displayed to the user. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// Content to append. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Stable opaque ID of the queued item to edit. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Optional POSIX-style mode for newly created files. + [JsonPropertyName("mode")] + public long? Mode { get; set; } - /// Replacement prompt sent to the model. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of withdrawing a user message. +/// Indicates whether the requested path exists in the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueWithdrawMessageResult +public sealed class SessionFsExistsResult { - /// True when the running turn was interrupted to withdraw the message. With removed false, the turn was interrupted but its events could not be removed, for example because the model answered first, so the message stays in the interrupted turn. - [JsonPropertyName("interrupted")] - public bool Interrupted { get; set; } - - /// True when the message left the queue or, for a running turn, history. - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// Whether the path exists. + [JsonPropertyName("exists")] + public bool Exists { get; set; } } -/// Conditional withdrawal of a single user message, from its queue or from the running turn it started. +/// Path to test for existence in the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueWithdrawMessageRequest +public sealed class SessionFsExistsRequest { - /// The prompt originally sent. A message edited since submission is not withdrawn, so an obsolete draft cannot replace the edit. - [JsonPropertyName("expectedPrompt")] - public string ExpectedPrompt { get; set; } = string.Empty; - - /// Message identity returned by send, not the queue item id. Batch messages are not eligible. - [JsonPropertyName("messageId")] - public string MessageId { get; set; } = string.Empty; + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Append to one pending steering message without changing its identity or delivery position. +/// Filesystem metadata for the requested path, or a filesystem error if the stat failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueAppendSteeringRequest +public sealed class SessionFsStatResult { - /// Mode captured at submission. Only steering messages in the same mode may be combined. - [JsonPropertyName("agentMode")] - public SendAgentMode AgentMode { get; set; } - - /// Attachments to add after the message's existing attachments. An empty list preserves the existing attachments. - [JsonPropertyName("attachments")] - public IList Attachments { get => field ??= []; set; } - - /// Display text to append to the existing preview after a blank line. - [JsonPropertyName("displayPrompt")] - public string DisplayPrompt { get; set; } = string.Empty; + /// ISO 8601 timestamp of creation. + [JsonPropertyName("birthtime")] + public DateTimeOffset Birthtime { get; set; } - /// Expected current prompt, including any previous appends. The runtime applies plan-mode normalization before comparing and refuses a changed message. - [JsonPropertyName("expectedPrompt")] - public string ExpectedPrompt { get; set; } = string.Empty; + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } - /// Message identity returned by send, not the queue item id. Only unclaimed user steering messages are eligible. - [JsonPropertyName("messageId")] - public string MessageId { get; set; } = string.Empty; + /// Whether the path is a directory. + [JsonPropertyName("isDirectory")] + public bool IsDirectory { get; set; } - /// Text to append after a blank line. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Whether the path is a file. + [JsonPropertyName("isFile")] + public bool IsFile { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// ISO 8601 timestamp of last modification. + [JsonPropertyName("mtime")] + public DateTimeOffset Mtime { get; set; } -/// Result of duplicating a queued item. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueDuplicateAtResult -{ - /// Fresh stable opaque id assigned to the duplicate. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// File size in bytes. + [JsonPropertyName("size")] + public long Size { get; set; } } -/// Parameters for duplicating a queued item. +/// Path whose metadata should be returned from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueDuplicateAtRequest +public sealed class SessionFsStatRequest { - /// Stable opaque ID of the queued item to duplicate. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Parameters for acquiring or releasing the queued-lane drain pause. Acquisition is exclusive and non-idempotent: `paused: true` against an already-paused session fails with `queue_already_paused`. The pause is never released automatically — it is not tied to the caller's lifetime, so a client that exits without sending `paused: false` leaves the lane frozen. Release is unowned: `paused: false` clears the pause for any caller, including one that never acquired it. +/// Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueSetDrainPausedRequest +public sealed class SessionFsMkdirRequest { - /// Whether queued-lane draining should be paused. - [JsonPropertyName("paused")] - public bool Paused { get; set; } + /// Optional POSIX-style mode for newly created directories. + [JsonPropertyName("mode")] + public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Create parent directories as needed. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of trying to steer a queued message into a live turn. +/// Names of entries in the requested directory, or a filesystem error if the read failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueSendNowResult +public sealed class SessionFsReaddirResult { - /// True when the item was accepted into the steering lane; false when no main turn was live. - [JsonPropertyName("steered")] - public bool Steered { get; set; } + /// Entry names in the directory. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } -/// Parameters for steering a queued message into a live turn. +/// Directory path whose entries should be listed from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueSendNowRequest +public sealed class SessionFsReaddirRequest { - /// Stable opaque ID of the queued item to steer into the live turn. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Whether the native queue has pending work. +/// Directory entry returned by session filesystem `readdirWithTypes`, with name and entry type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueHasPendingResult +public sealed class SessionFsReaddirWithTypesEntry { - /// True when queued or immediate native work is pending. - [JsonPropertyName("hasPending")] - public bool HasPending { get; set; } -} + /// Entry name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueHasPendingRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Entry type. + [JsonPropertyName("type")] + public SessionFsReaddirWithTypesEntryType Type { get; set; } } -/// Whether a deferred-idle drain should run. +/// Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueBeginDeferredIdleDrainResult +public sealed class SessionFsReaddirWithTypesResult { - /// True when the host should run finishDeferredIdleDrain asynchronously. - [JsonPropertyName("shouldDrain")] - public bool ShouldDrain { get; set; } + /// Directory entries with type information. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } -/// Inputs for starting a deferred-idle drain. +/// Directory path whose entries (with type information) should be listed from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueBeginDeferredIdleDrainRequest +public sealed class SessionFsReaddirWithTypesRequest { - /// Whether the host still has active background work. - [JsonPropertyName("activeBackgroundWork")] - public bool ActiveBackgroundWork { get; set; } + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Action selected by the native deferred-idle drain. +/// Path to remove from the client-provided session filesystem, with options for recursive removal and force. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueFinishDeferredIdleDrainResult +public sealed class SessionFsRmRequest { - /// Whether the deferred idle was caused by an aborted foreground turn. - [JsonPropertyName("aborted")] - public bool Aborted { get; set; } - - /// One of none, processQueue, or emitSessionIdle. - [JsonPropertyName("action")] - public string Action { get; set; } = string.Empty; -} + /// Ignore errors if the path does not exist. + [JsonPropertyName("force")] + public bool? Force { get; set; } -/// Inputs for completing a deferred-idle drain. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueFinishDeferredIdleDrainRequest -{ - /// Whether the host still has active background work. - [JsonPropertyName("activeBackgroundWork")] - public bool ActiveBackgroundWork { get; set; } + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Whether native queued work remains. - [JsonPropertyName("hasPending")] - public bool HasPending { get; set; } + /// Remove directories and their contents recursively. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Inputs for marking session.idle deferred in native state. +/// Source and destination paths for renaming or moving an entry in the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueDeferSessionIdleRequest +public sealed class SessionFsRenameRequest { - /// Whether the deferred idle was caused by an aborted foreground turn. - [JsonPropertyName("aborted")] - public bool Aborted { get; set; } + /// Destination path using SessionFs conventions. + [JsonPropertyName("dest")] + public string Dest { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Source path using SessionFs conventions. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; } -/// Indicates whether a user-facing pending item was removed. +/// Query results including rows, columns, and rows affected, or a filesystem error if execution failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueRemoveMostRecentResult +public sealed class SessionFsSqliteQueryResult { - /// True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// Column names from the result set. + [JsonPropertyName("columns")] + public IList Columns { get => field ??= []; set; } + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } + + /// SQLite last_insert_rowid() value for INSERT. + [JsonPropertyName("lastInsertRowid")] + public long? LastInsertRowid { get; set; } + + /// For SELECT: array of row objects. For others: empty array. + [JsonPropertyName("rows")] + public IList> Rows { get => field ??= []; set; } + + /// Number of rows affected (for INSERT/UPDATE/DELETE). + [JsonPropertyName("rowsAffected")] + public long RowsAffected { get; set; } } -/// Identifies the target session. +/// SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. The provider applies its SQLite busy timeout for every call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueRemoveMostRecentRequest +public sealed class SessionFsSqliteQueryRequest { + /// Optional named bind parameters. + [JsonPropertyName("params")] + public IDictionary? Params { get; set; } + + /// SQL query to execute. + [JsonPropertyName("query")] + public string Query { get; set; } = string.Empty; + + /// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected). + [JsonPropertyName("queryType")] + public SessionFsSqliteQueryType QueryType { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Classified SQLite transaction failure. busyOrLocked guarantees rollback; postCommitAmbiguous must never be retried. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueClearRequest +public sealed class SessionFsSqliteTransactionError { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Machine-readable classification of the transaction failure. + [JsonPropertyName("errorClass")] + public SessionFsSqliteTransactionErrorClass ErrorClass { get; set; } + + /// Human-readable transaction failure message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// Internal filter for consuming queued system notifications. +/// Per-statement results, or a classified transaction error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueConsumeSystemNotificationsRequest +public sealed class SessionFsSqliteTransactionResult { - /// Opaque runtime-owned filter object. - [JsonPropertyName("filter")] - public JsonElement Filter { get; set; } + /// Classified transaction failure, when execution did not succeed. + [JsonPropertyName("error")] + public SessionFsSqliteTransactionError? Error { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Per-statement query results in input order. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } } -/// Result of enqueueing the resume-pending wake item. +/// One statement in an atomic SQLite transaction. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueEnqueueResumePendingResult +public sealed class SessionFsSqliteTransactionStatement { - /// True when a wake item was newly queued. - [JsonPropertyName("queued")] - public bool Queued { get; set; } + /// Optional named bind parameters. + [JsonPropertyName("params")] + public IDictionary? Params { get; set; } + + /// SQL statement to execute. + [JsonPropertyName("query")] + public string Query { get; set; } = string.Empty; + + /// How to execute the statement. + [JsonPropertyName("queryType")] + public SessionFsSqliteQueryType QueryType { get; set; } } -/// Identifies the target session. +/// Statements to execute atomically. Providers apply busy handling for every call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueEnqueueResumePendingRequest +public sealed class SessionFsSqliteTransactionRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Ordered SQL statements to execute in one transaction. + [JsonPropertyName("statements")] + public IList Statements { get => field ??= []; set; } } -/// Identifies the target session. +/// Indicates whether the per-session SQLite database already exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueProcessRequest +public sealed class SessionFsSqliteExistsResult +{ + /// Whether the session database already exists. + [JsonPropertyName("exists")] + public bool Exists { get; set; } +} + +/// Identifies the target session. +public sealed class SessionFsSqliteExistsRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Cursor, batch size, and optional long-poll/filter parameters for reading session events. +/// Canvas open result returned by the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EventLogReadRequest +public sealed class CanvasProviderOpenResult { - /// Optional non-empty list of subagent identifiers. When provided, only events owned by one of these agents are returned; ownership recognizes the event envelope's agentId plus legacy data.agentId and data.parentToolCallId markers. This filter takes precedence over agentScope. - [JsonPropertyName("agentIds")] - public IList? AgentIds { get; set; } - - /// Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. - [JsonPropertyName("agentScope")] - public EventsAgentScope? AgentScope { get; set; } - - /// Opaque cursor returned by a previous read. Omit on the first call to start from the beginning of the session's persisted history. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } - - /// Direction to page through the session's persisted event history. 'forward' (default) pages from the cursor toward newer events (or from the start of history when no cursor is given). 'backward' enables tail-first reads: with no cursor it returns the NEWEST `max` events, and the returned cursor pages toward OLDER events on subsequent backward reads. Events within a returned batch are always in chronological (oldest-to-newest) order, even for a backward read. Backward reads cover PERSISTED history only; ephemeral events are never returned by a backward read. `direction` selects the INITIAL read only: the returned cursor is self-describing, so a continuation read pages in the cursor's own direction regardless of the `direction` passed alongside it — a forward cursor always pages forward and a backward cursor always pages backward. Pass the direction that matches the cursor to avoid confusion. - [JsonPropertyName("direction")] - public EventsReadDirection? Direction { get; set; } - - /// When false, skip ephemeral events entirely and return only durable (persisted) events. History-backfill callers that discard ephemerals anyway should set this so the read is bounded by the durable log length instead of racing the ephemeral ring on a busy session. Defaults to true (ephemerals are interleaved with durable events in creation order). Ignored by backward reads, which always cover persisted history only. - [JsonPropertyName("includeEphemeral")] - public bool? IncludeEphemeral { get; set; } - - /// Maximum number of events to return in this batch (1–1000, default 200). - [JsonPropertyName("max")] - public long? Max { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Provider-supplied status text. + [JsonPropertyName("status")] + public string? Status { get; set; } - /// Either '*' to receive all event types, or a non-empty list of event types to receive. - [JsonPropertyName("types")] - public JsonElement? Types { get; set; } + /// Provider-supplied title. + [JsonPropertyName("title")] + public string? Title { get; set; } - /// Milliseconds to wait for new events when the cursor is at the tail of history. 0 (default) returns immediately even if no events are available. Capped at 30000ms. Ephemeral events that arrive during the wait are delivered in this batch but are NOT replayable on a subsequent read (use a non-zero waitMs in your next call to capture future ephemerals as they happen). This applies to forward reads only: a backward read always returns immediately and ignores `waitMs`, because backward paging covers persisted history only while new events append at the tail (the opposite end from a backward page), so no blocking or ephemeral delivery can occur. - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("waitMs")] - public TimeSpan? Wait { get; set; } + /// URL for web-rendered canvases. + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// Snapshot of the current tail cursor without returning any events. Use this when 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). +/// Host capabilities. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EventLogTailResult +public sealed class CanvasHostContextCapabilities { - /// Opaque cursor pointing at the current tail of the session's persisted-events history. Pass back to `read` to receive only events that arrive AFTER this snapshot. When the session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent to omitting the cursor on a first read). - [JsonPropertyName("cursor")] - public string Cursor { get; set; } = string.Empty; + /// Whether canvas rendering is supported. + [JsonPropertyName("canvases")] + public bool? Canvases { get; set; } } -/// Identifies the target session. +/// Host context supplied by the runtime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionEventLogTailRequest +public sealed class CanvasHostContext { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Host capabilities. + [JsonPropertyName("capabilities")] + public CanvasHostContextCapabilities? Capabilities { get; set; } } -/// Opaque handle representing an event-type interest registration. +/// Session context supplied by the runtime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RegisterEventInterestResult +public sealed class CanvasSessionContext { - /// Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; + /// Active session working directory, when known. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Event type to register consumer interest for, used by runtime gating logic. +/// Canvas open parameters sent to the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RegisterEventInterestParams +public sealed class CanvasProviderOpenRequest { - /// The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates interactive OAuth token acquisition to the consumer via `mcp.oauth_required` events; when no interest is registered the runtime still attempts non-interactive reconnect from cached or refreshable tokens, and only marks the server `needs-auth` if usable credentials are unavailable — it does not open a browser or start interactive OAuth without a consumer). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `session_limits_exhausted.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. - [JsonPropertyName("eventType")] - public string EventType { get; set; } = string.Empty; + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; + + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; + + /// Host context supplied by the runtime. + [JsonPropertyName("host")] + public CanvasHostContext? Host { get; set; } + + /// Canvas open input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } + + /// Stable caller-supplied canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + + /// Session context supplied by the runtime. + [JsonPropertyName("session")] + public CanvasSessionContext? Session { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// Canvas close parameters sent to the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EventLogReleaseInterestResult +public sealed class CanvasProviderCloseRequest { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; -/// Opaque handle previously returned by `registerInterest` to release. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ReleaseEventInterestParams -{ - /// Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; + + /// Host context supplied by the runtime. + [JsonPropertyName("host")] + public CanvasHostContext? Host { get; set; } + + /// Canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + + /// Session context supplied by the runtime. + [JsonPropertyName("session")] + public CanvasSessionContext? Session { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Request count and cost metrics for this model. +/// Canvas action invocation parameters sent to the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageMetricsModelMetricRequests +public sealed class CanvasProviderInvokeActionRequest { - /// User-initiated premium request cost (with multiplier applied). - [JsonPropertyName("cost")] - public double Cost { get; set; } + /// Action name to invoke. + [JsonPropertyName("actionName")] + public string ActionName { get; set; } = string.Empty; - /// Number of API requests made with this model. - [JsonPropertyName("count")] - public long Count { get; set; } -} + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; + + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; + + /// Host context supplied by the runtime. + [JsonPropertyName("host")] + public CanvasHostContext? Host { get; set; } + + /// Action input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } + + /// Canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + + /// Session context supplied by the runtime. + [JsonPropertyName("session")] + public CanvasSessionContext? Session { get; set; } -/// Per-model token-detail entry containing the accumulated token count for one token type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageMetricsModelMetricTokenDetail -{ - /// Accumulated token count for this token type. - [JsonPropertyName("tokenCount")] - public long TokenCount { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Token usage metrics for this model. +/// Reports a supervised listener's hosting-task termination and cleanup outcome. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageMetricsModelMetricUsage +public sealed class HostExitedRequest { - /// Total tokens read from prompt cache. - [JsonPropertyName("cacheReadTokens")] - public long CacheReadTokens { get; set; } - - /// Total tokens written to prompt cache. - [JsonPropertyName("cacheWriteTokens")] - public long CacheWriteTokens { get; set; } + /// Explicit startup or teardown failure, when present. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Total input tokens consumed. - [JsonPropertyName("inputTokens")] - public long InputTokens { get; set; } + /// Process exit status when available; absent for in-process listener tasks. + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } - /// Total output tokens produced. - [JsonPropertyName("outputTokens")] - public long OutputTokens { get; set; } + /// Listener UUID. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; - /// Total output tokens used for reasoning. - [JsonPropertyName("reasoningTokens")] - public long? ReasoningTokens { get; set; } + /// Cause of termination. + [JsonPropertyName("reason")] + public HostExitReason Reason { get; set; } } -/// Per-model usage metrics, including request counts/costs, token usage, nano-AI units, and per-token-type details. +/// Opaque integrator-owned process launch profile for one extension entrypoint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageMetricsModelMetric +public sealed class ExtensionLaunchProfile { - /// Latest known prompt-cache expiration for this model. A timestamp in the past indicates that the observed cache has expired. - [JsonPropertyName("cacheExpiresAt")] - public DateTimeOffset? CacheExpiresAt { get; set; } - - /// Request count and cost metrics for this model. - [JsonPropertyName("requests")] - public UsageMetricsModelMetricRequests Requests { get => field ??= new(); set; } - - /// Token count details per type. - [JsonPropertyName("tokenDetails")] - public IDictionary? TokenDetails { get; set; } + /// Opaque integrator-defined arguments passed to the executable. The runtime does not append the extension entrypoint. + [JsonPropertyName("args")] + public IList Args { get => field ??= []; set; } - /// Accumulated nano-AI units cost for this model. - [JsonPropertyName("totalNanoAiu")] - public double? TotalNanoAiu { get; set; } + /// Opaque integrator-defined environment variables. Runtime-owned COPILOT_SDK_PATH, SESSION_ID, and COPILOT_EXTENSION_PARENT_PID values take precedence. + [JsonPropertyName("env")] + public IDictionary Env { get => field ??= new Dictionary(); set; } - /// Token usage metrics for this model. - [JsonPropertyName("usage")] - public UsageMetricsModelMetricUsage Usage { get => field ??= new(); set; } + /// Executable used to launch the extension entrypoint. + [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("executable")] + public string Executable { get; set; } = string.Empty; } -/// Usage attributed to one agent instance, including its identity, API duration, AI units, and per-model breakdown. +/// The launch profile for a supported entrypoint. Omit launch when the provider does not support the entrypoint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageMetricsAgentMetric +public sealed class ExtensionLaunchProviderResolveResult { - /// Human-readable label for this subagent invocation, copied from the originating `subagent.started` event. For task-tool subagents this is the invocation's task description rather than the agent's configured display name, so group by `agentName` for stable per-agent labels. - [JsonPropertyName("agentDisplayName")] - public string? AgentDisplayName { get; set; } - - /// Configured agent name, when this is a subagent. - [JsonPropertyName("agentName")] - public string? AgentName { get; set; } - - /// Per-model usage for this agent, keyed by model identifier. - [JsonPropertyName("modelMetrics")] - public IDictionary ModelMetrics { get => field ??= new Dictionary(); set; } - - /// Time spent in model API calls by this agent, in milliseconds. - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("totalApiDurationMs")] - public TimeSpan TotalApiDuration { get; set; } - - /// Accumulated nano-AI units cost for this agent. - [JsonPropertyName("totalNanoAiu")] - public double TotalNanoAiu { get; set; } + /// Opaque launch profile, omitted when this provider does not support the entrypoint. + [JsonPropertyName("launch")] + public ExtensionLaunchProfile? Launch { get; set; } } -/// Aggregated code change metrics. +/// A discovered extension entrypoint that the registered integrator may classify and resolve to an opaque launch profile. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageMetricsCodeChanges +public sealed class ExtensionLaunchProviderResolveRequest { - /// Distinct file paths modified during the session. - [JsonPropertyName("filesModified")] - public IList FilesModified { get => field ??= []; set; } + /// Source-qualified extension identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Number of distinct files modified. - [JsonPropertyName("filesModifiedCount")] - public long FilesModifiedCount { get; set; } + /// Absolute path to the discovered extension entrypoint. + [JsonPropertyName("modulePath")] + public string ModulePath { get; set; } = string.Empty; - /// Total lines of code added. - [JsonPropertyName("linesAdded")] - public long LinesAdded { get; set; } + /// Human-readable extension name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Total lines of code removed. - [JsonPropertyName("linesRemoved")] - public long LinesRemoved { get; set; } + /// Discovery source for the extension entrypoint. + [JsonPropertyName("source")] + public ExtensionSource Source { get; set; } } -/// Session-wide token-detail entry containing the accumulated token count for one token type. +/// Acknowledgement. Returning successfully simply means the SDK accepted the start frame; it does not imply the request will succeed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageMetricsTokenDetail +public sealed class LlmInferenceHttpRequestStartResult { - /// Accumulated token count for this token type. - [JsonPropertyName("tokenCount")] - public long TokenCount { get; set; } } -/// Accumulated session usage metrics, including premium request cost, token counts, model breakdown, and code-change totals. +/// The head of an outbound model-layer HTTP request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UsageGetMetricsResult +public sealed class LlmInferenceHttpRequestStartRequest { - /// Per-agent usage metrics, keyed by agent instance identifier. The main conversation uses the stable key `main`. - [JsonPropertyName("agentMetrics")] - public IDictionary? AgentMetrics { get; set; } - - /// Aggregated code change metrics. - [JsonPropertyName("codeChanges")] - public UsageMetricsCodeChanges CodeChanges { get => field ??= new(); set; } - - /// Currently active model identifier. - [JsonPropertyName("currentModel")] - public string? CurrentModel { get; set; } + /// Stable identity of the agent trajectory that issued this request. Present when the request originates from an agent turn; absent for requests outside any agent context. This is the same identity used by lifecycle and bridged session events and remains constant across turns and retries. + [JsonPropertyName("agentId")] + public string? AgentId { get; set; } - /// Input tokens from the most recent main-agent API call. - [JsonPropertyName("lastCallInputTokens")] - public long LastCallInputTokens { get; set; } + /// Identity of the agent invocation (one agentic loop) that issued this request. It remains fixed across physical retries within the invocation and is distinct from the stable trajectory `agentId`. A caller-supplied invocation id always takes precedence (this covers auxiliary calls that have no model call id). Otherwise, first-party CAPI requests fall back to the runtime's agent task id — the same value the runtime emits as the `X-Agent-Task-Id` header — while custom-provider requests fall back to the model call id. + [JsonPropertyName("agentInvocationId")] + public string? AgentInvocationId { get; set; } - /// Output tokens from the most recent main-agent API call. - [JsonPropertyName("lastCallOutputTokens")] - public long LastCallOutputTokens { get; set; } + /// HTTP request headers, preserving multiple values per name. + [JsonPropertyName("headers")] + public IDictionary> Headers { get => field ??= new Dictionary>(); set; } - /// Per-model token and request metrics, keyed by model identifier. - [JsonPropertyName("modelMetrics")] - public IDictionary ModelMetrics { get => field ??= new Dictionary(); set; } + /// Coarse classification of the interaction that produced this request. Open string for forward-compatibility; known values include `conversation-agent`, `conversation-subagent`, `conversation-sampling`, `conversation-background`, `conversation-compaction`, and `conversation-user`. Absent when the runtime did not classify the request. Comes from the runtime's per-request agent context independently of transport; on the CAPI transport the runtime derives the upstream `X-Interaction-Type` header from this same context. + [JsonPropertyName("interactionType")] + public string? InteractionType { get; set; } - /// ISO 8601 timestamp when the session started. - [JsonPropertyName("sessionStartTime")] - public DateTimeOffset SessionStartTime { get; set; } + /// HTTP method, e.g. GET, POST. + [JsonPropertyName("method")] + public string Method { get; set; } = string.Empty; - /// Session-wide per-token-type accumulated token counts. - [JsonPropertyName("tokenDetails")] - public IDictionary? TokenDetails { get; set; } + /// Stable identity of the immediate parent trajectory. Present for child trajectories such as subagents and conversation-sampling requests; absent for root-agent and non-agent requests. + [JsonPropertyName("parentAgentId")] + public string? ParentAgentId { get; set; } - /// Total time spent in model API calls (milliseconds). - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("totalApiDurationMs")] - public TimeSpan TotalApiDuration { get; set; } + /// Opaque runtime-minted id, unique per in-flight request. The SDK uses this to correlate httpRequestChunk frames and to address its httpResponseStart / httpResponseChunk replies back to the runtime. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Session-wide accumulated nano-AI units cost. - [JsonPropertyName("totalNanoAiu")] - public double? TotalNanoAiu { get; set; } + /// Id of the runtime session that triggered this request, when one is in scope. Absent for requests issued outside any session (e.g. startup model-catalog or capability resolution). This is a payload field — not a dispatch key — because the client-global API is registered process-wide rather than per session. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } - /// Total user-initiated premium request cost across all models (may be fractional due to multipliers). - [JsonPropertyName("totalPremiumRequestCost")] - public double TotalPremiumRequestCost { get; set; } + /// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. + [JsonPropertyName("transport")] + public LlmInferenceHttpRequestStartTransport? Transport { get; set; } - /// Raw count of user-initiated API requests. - [JsonPropertyName("totalUserRequests")] - public long TotalUserRequests { get; set; } + /// Absolute request URL. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// Identifies the target session. +/// Acknowledgement. The SDK is free to ignore the ack and treat chunk delivery as fire-and-forget. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionUsageGetMetricsRequest +public sealed class LlmInferenceHttpRequestChunkResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; } -/// Prediction result. Available results include prediction details; unavailable results include an explicit reason. -/// Polymorphic base type discriminated by kind. +/// A request body chunk or cancellation signal. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SessionLimitPredictionResultAvailable), "available")] -[JsonDerivedType(typeof(SessionLimitPredictionResultUnavailable), "unavailable")] -public partial class SessionLimitPredictionResult +public sealed class LlmInferenceHttpRequestChunkRequest { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Identity of the agent invocation (one agentic loop) this body chunk belongs to, matching the `agentInvocationId` semantics on httpRequestStart. Carried per chunk so a persistent transport can attribute successive turns correctly: when a WebSocket connection is reused across turns, the httpRequestStart identity reflects only the turn that opened the connection, so each later turn stamps its own invocation id here. Absent when the runtime has no invocation context for the request, or on the plain-HTTP transport where every request has its own httpRequestStart. + [JsonPropertyName("agentInvocationId")] + public string? AgentInvocationId { get; set; } + /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. + [JsonPropertyName("binary")] + public bool? Binary { get; set; } -/// Baseline data provenance for a prediction. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionBaselineData -{ - /// End of the baseline data slice. - [JsonPropertyName("windowEnd")] - public string WindowEnd { get; set; } = string.Empty; + /// When true, the runtime is cancelling the in-flight request (e.g. upstream consumer aborted). `data` is ignored. Implies end-of-request. + [JsonPropertyName("cancel")] + public bool? Cancel { get; set; } - /// Start of the baseline data slice. - [JsonPropertyName("windowStart")] - public string WindowStart { get; set; } = string.Empty; -} + /// Optional human-readable reason for the cancellation, propagated for logging. + [JsonPropertyName("cancelReason")] + public string? CancelReason { get; set; } -/// Semantic usage tier and its AI-credit cap. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionTierOption -{ - /// AI-credit cap for this tier. - [JsonPropertyName("cap")] - public double Cap { get; set; } + /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty. + [JsonPropertyName("data")] + public string Data { get; set; } = string.Empty; - /// Semantic usage tier. - [JsonPropertyName("tier")] - public SessionLimitPredictionTier Tier { get; set; } + /// When true, this is the final body chunk for the request. The SDK may rely on having received an end-marked chunk before treating the request body as complete. + [JsonPropertyName("end")] + public bool? End { get; set; } + + /// Matches the requestId from the originating httpRequestStart frame. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; } -/// Explainable AI-credit session-limit prediction. +/// Client environment metadata describing the process that produced a telemetry event. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionDetails +public sealed class GitHubTelemetryClientInfo { - /// Baseline data provenance. - [JsonPropertyName("baselineData")] - public SessionLimitPredictionBaselineData BaselineData { get => field ??= new(); set; } - - /// Client population used for the prediction. - [JsonPropertyName("clientType")] - public SessionLimitPredictionClientType ClientType { get; set; } + /// Copilot CLI version string. + [JsonPropertyName("cli_version")] + public string CliVersion { get; set; } = string.Empty; - /// Resolved model family when known. - [JsonPropertyName("family")] - public string? Family { get; set; } + /// Name of the client application. + [JsonPropertyName("client_name")] + public string? ClientName { get; set; } - /// Model identifier used for lookup. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; + /// Type of client. + [JsonPropertyName("client_type")] + public string? ClientType { get; set; } - /// Recommended maximum AI credits for this session. - [JsonPropertyName("recommendedCap")] - public double RecommendedCap { get; set; } + /// Copilot subscription plan, when known. + [JsonPropertyName("copilot_plan")] + public string? CopilotPlan { get; set; } - /// Tier chosen as the recommended cap. - [JsonPropertyName("recommendedTier")] - public SessionLimitPredictionTier RecommendedTier { get; set; } + /// Number of logical CPU cores on the host. + [JsonPropertyName("cpu_count")] + public long? CpuCount { get; set; } - /// Baseline fallback level used to create the prediction. - [JsonPropertyName("source")] - public SessionLimitPredictionSource Source { get; set; } + /// Distinct CPU model names for the host, comma-separated. + [JsonPropertyName("cpu_model")] + public string? CpuModel { get; set; } - /// Key matched at the source level, such as a model id, family id, or `global`. - [JsonPropertyName("sourceKey")] - public string SourceKey { get; set; } = string.Empty; + /// Stable machine identifier for the device. + [JsonPropertyName("dev_device_id")] + public string? DevDeviceId { get; set; } - /// Ordered usage tiers and their AI-credit caps. - [JsonPropertyName("tiers")] - public IList Tiers { get => field ??= []; set; } -} + /// Whether the user is a GitHub/Microsoft staff member. + [JsonPropertyName("is_staff")] + public bool? IsStaff { get; set; } -/// The available variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionLimitPredictionResultAvailable : SessionLimitPredictionResult -{ - /// - [JsonIgnore] - public override string Kind => "available"; + /// Node.js runtime version string. + [JsonPropertyName("node_version")] + public string NodeVersion { get; set; } = string.Empty; - /// Predicted session limit details. - [JsonPropertyName("prediction")] - public required SessionLimitPredictionDetails Prediction { get; set; } -} + /// Operating system architecture (e.g. arm64, x64). + [JsonPropertyName("os_arch")] + public string OsArch { get; set; } = string.Empty; -/// The unavailable variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionLimitPredictionResultUnavailable : SessionLimitPredictionResult -{ - /// - [JsonIgnore] - public override string Kind => "unavailable"; + /// Operating system platform (e.g. darwin, linux, win32). + [JsonPropertyName("os_platform")] + public string OsPlatform { get; set; } = string.Empty; - /// Reason no prediction is available. - [JsonPropertyName("reason")] - public required SessionLimitPredictionUnavailableReason Reason { get; set; } + /// Operating system version string. + [JsonPropertyName("os_version")] + public string OsVersion { get; set; } = string.Empty; } -/// RPC data type for SessionLimitPredictionPredict operations. +/// A single telemetry event in the runtime's native GitHub-shaped telemetry format, forwarded verbatim to opted-in hosts. The `restricted` flag on the enclosing GitHubTelemetryNotification distinguishes standard from restricted events; the payload shape is identical for both. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionPredictRequest +public sealed class GitHubTelemetryEvent { - /// Client type to size for. Defaults to `cli-interactive`. - [JsonPropertyName("clientType")] - public SessionLimitPredictionClientType? ClientType { get; set; } + /// Client environment metadata. + [JsonPropertyName("client")] + public GitHubTelemetryClientInfo? Client { get; set; } - /// Optional model identifier override. If omitted, the session's current model is used. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } -} + /// Copilot tracking ID for user-level attribution. + [JsonPropertyName("copilot_tracking_id")] + public string? CopilotTrackingId { get; set; } -/// RPC data type for SessionLimitPredictionPredictRequestWithSession operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionLimitPredictionPredictRequestWithSession -{ - /// Client type to size for. Defaults to `cli-interactive`. - [JsonPropertyName("clientType")] - public SessionLimitPredictionClientType? ClientType { get; set; } + /// Timestamp when the event was created (ISO 8601 format). + [JsonPropertyName("created_at")] + public string? CreatedAt { get; set; } - /// Optional model identifier override. If omitted, the session's current model is used. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Experiment assignment context. + [JsonPropertyName("exp_assignment_context")] + public string? ExpAssignmentContext { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Feature flags enabled for this session, as a map from flag to value. + [JsonPropertyName("features")] + public IDictionary? Features { get; set; } -/// GitHub URL for the session and a flag indicating whether remote steering is enabled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteEnableResult -{ - /// Whether remote steering is enabled. - [JsonPropertyName("remoteSteerable")] - public bool RemoteSteerable { get; set; } + /// Event type/kind (e.g. get_completion_with_tools_turn, tool_call_executed). + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; - /// GitHub frontend URL for this session. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("url")] - public string? Url { get; set; } -} + /// Numeric metrics as a map from key to value. + [JsonPropertyName("metrics")] + public IDictionary Metrics { get => field ??= new Dictionary(); set; } -/// Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RemoteEnableRequest -{ - /// Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. - [JsonPropertyName("mode")] - public RemoteSessionMode? Mode { get; set; } + /// Reference to the model call that produced this event. + [JsonPropertyName("model_call_id")] + public string? ModelCallId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// String-valued properties as a map from key to value. + [JsonPropertyName("properties")] + public IDictionary Properties { get => field ??= new Dictionary(); set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionRemoteDisableRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Session identifier the event belongs to. + [JsonPropertyName("session_id")] + public string? SessionId { get; set; } } -/// 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. +/// Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry event the runtime forwards to a host connection that opted into telemetry forwarding during the `server.connect` handshake. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteNotifySteerableChangedResult +public sealed class GitHubTelemetryNotification { -} + /// The telemetry event, in the runtime's native GitHub-shaped telemetry format. + [JsonPropertyName("event")] + public GitHubTelemetryEvent Event { get => field ??= new(); set; } -/// New remote-steerability state to persist as a `session.remote_steerable_changed` event. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RemoteNotifySteerableChangedRequest -{ - /// Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. - [JsonPropertyName("remoteSteerable")] - public bool RemoteSteerable { get; set; } + /// Whether this is a restricted telemetry event (cli.restricted_telemetry). Hosts must route restricted events to first-party Microsoft stores only. + [JsonPropertyName("restricted")] + public bool Restricted { get; set; } - /// Target session identifier. + /// Session the telemetry event belongs to, when it is session-scoped. Omitted for sessionless events (for example, `server.sendTelemetry` calls with no session id), which are still forwarded to opted-in connections. [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public string? SessionId { get; set; } } -/// Current sharing status and shareable GitHub URL for a session. +/// SDK host response to a GitHub credential request. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class VisibilityGetResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(GitHubTokenAcquireResultToken), "token")] +[JsonDerivedType(typeof(GitHubTokenAcquireResultCancelled), "cancelled")] +public partial class GitHubTokenAcquireResult { - /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("shareUrl")] - public string? ShareUrl { get; set; } - - /// Current sharing status. Absent when the session is not synced or the status could not be retrieved (e.g. the user is not authenticated). - [JsonPropertyName("status")] - public SessionVisibilityStatus? Status { get; set; } - - /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the session cannot be shared and `status`/`shareUrl` are absent. - [JsonPropertyName("synced")] - public bool Synced { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionVisibilityGetRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} -/// Effective sharing status and shareable GitHub URL after updating session visibility. +/// The token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class VisibilitySetResult +public partial class GitHubTokenAcquireResultToken : GitHubTokenAcquireResult { - /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("shareUrl")] - public string? ShareUrl { get; set; } + /// + [JsonIgnore] + public override string Kind => "token"; - /// Effective sharing status after the update. May differ from the requested status for task types that are already visible to repository readers by default. Absent when the update could not be applied (e.g. the session is not synced or the user is not authenticated). - [JsonPropertyName("status")] - public SessionVisibilityStatus? Status { get; set; } + /// GitHub access token acquired by the SDK host. + [JsonPropertyName("accessToken")] + public required string AccessToken { get; set; } - /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the visibility change could not be applied and `status`/`shareUrl` are absent. - [JsonPropertyName("synced")] - public bool Synced { get; set; } + /// Remaining token lifetime in seconds when callback execution completes. It must exceed the one-hour preflight refresh threshold. + [JsonPropertyName("expiresIn")] + public required long ExpiresIn { get; set; } + + /// OAuth token type. Defaults to bearer when omitted. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("tokenType")] + public string? TokenType { get; set; } } -/// Desired sharing status for the session. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class VisibilitySetRequest +public partial class GitHubTokenAcquireResultCancelled : GitHubTokenAcquireResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - - /// Sharing status to apply. "repo" makes the session visible to repository readers; "unshared" restricts it to the creator and collaborators. - [JsonPropertyName("status")] - public SessionVisibilityStatus Status { get; set; } + /// + [JsonIgnore] + public override string Kind => "cancelled"; } -/// Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text, recurrence, and next run time. +/// Asks the SDK client to acquire a GitHub access token from an opaque callback registration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ScheduleEntry +public sealed class GitHubTokenAcquireRequest { - /// Absolute fire time (epoch milliseconds) for a one-shot calendar schedule. - [JsonPropertyName("at")] - public long? At { get; set; } - - /// 5-field cron expression for a recurring calendar schedule, evaluated in `tz`. - [JsonPropertyName("cron")] - public string? Cron { get; set; } - - /// Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } - - /// Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). - [JsonPropertyName("id")] - public long Id { get; set; } - - /// Interval between scheduled ticks, in milliseconds (relative-interval schedules). - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("intervalMs")] - public TimeSpan? Interval { get; set; } - - /// ISO 8601 timestamp when the next tick is scheduled to fire. - [JsonPropertyName("nextRunAt")] - public DateTimeOffset NextRunAt { get; set; } - - /// Prompt text that gets enqueued on every tick. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; - - /// Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). - [JsonPropertyName("recurring")] - public bool Recurring { get; set; } - - /// True for a self-paced (`dynamic`) schedule: no fixed cadence; the model arms each next run via the `manage_schedule` `wakeup` action. `nextRunAt` is model-controlled. - [JsonPropertyName("selfPaced")] - public bool? SelfPaced { get; set; } + /// Effective GitHub host for which the callback must return a token. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// IANA timezone the `cron` expression is evaluated in. - [JsonPropertyName("tz")] - public string? Tz { get; set; } -} + /// Why the runtime is requesting a GitHub credential. + [JsonPropertyName("reason")] + public GitHubTokenAcquireReason Reason { get; set; } -/// Snapshot of the currently active recurring prompts for this session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ScheduleList -{ - /// Active scheduled prompts, ordered by id. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } -} + /// Opaque identifier generated by the SDK for this callback registration. + [JsonPropertyName("registrationId")] + public string RegistrationId { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionScheduleListRequest -{ - /// Target session identifier. + /// Session receiving the token. Absent only before a cloud session has been assigned its id. [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public string? SessionId { get; set; } } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionScheduleHydrateRequest +/// A response is meaningful only on the connection and request that issued its challenge. +public sealed class InstallationsConfirmResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Exact challenge from the request. + [JsonPropertyName("confirmationId")] + public string ConfirmationId { get; set; } = string.Empty; + + /// Fresh explicit user decision. There is no default. + [JsonPropertyName("decision")] + public InstallationDecision Decision { get; set; } + + /// Exact review commitment from the request. + [JsonPropertyName("reviewFingerprint")] + public string ReviewFingerprint { get; set; } = string.Empty; } -/// Whether the session currently has an active self-paced schedule. +/// Only resource kinds with an implemented installation engine have a review variant. +/// Polymorphic base type discriminated by resource. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleHasSelfPacedResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "resource", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(InstallationReviewMcp), "mcp")] +[JsonDerivedType(typeof(InstallationReviewSkill), "skill")] +public partial class InstallationReview { - /// True when at least one active schedule is self-paced. - [JsonPropertyName("hasSelfPaced")] - public bool HasSelfPaced { get; set; } + /// The type discriminator. + [JsonPropertyName("resource")] + public virtual string Resource { get; set; } = string.Empty; } -/// Identifies the target session. + +/// Safe MCP review fields. No raw card, retrieval URL, plan handle or secret value. +/// Polymorphic base type discriminated by action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionScheduleHasSelfPacedRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "action", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationReviewInstall), "install")] +[JsonDerivedType(typeof(McpInstallationReviewUninstall), "uninstall")] +public partial class McpInstallationReview { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("action")] + public virtual string Action { get; set; } = string.Empty; } -/// Result of registering or re-arming a scheduled prompt. + +/// +/// Final remote configuration, not a template. The producer refuses external-value +/// expansion before presenting this review. Receipt-owned secrets appear only as +/// `${installation-secret:<id>}` references whose `<id>` matches a reviewed +/// `${secret:<id>}` placeholder; values are never included. +/// [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddResult +public sealed class McpInstallationRemoteConfiguration { - /// The registered or updated schedule entry. - [JsonPropertyName("entry")] - public ScheduleEntry? Entry { get; set; } + /// + /// Configured headers, excluding separately authorised OAuth tokens. Values may + /// contain owned secret references, never secret values. + /// + [JsonPropertyName("headers")] + public IDictionary Headers { get => field ??= new Dictionary(); set; } - /// User-facing validation error, when registration failed. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Configured tool selection, not permission to invoke those tools. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } + + /// Transport in the effective persisted remote configuration. + [JsonPropertyName("transport")] + public McpPlanRemoteTransport Transport { get; set; } + + /// Exact resolved endpoint, without templates or secret placeholders. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// Register a relative-interval scheduled prompt. +/// The install variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddRequest +public partial class McpInstallationReviewInstall : McpInstallationReview { - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// + [JsonIgnore] + public override string Action => "install"; - /// Human-readable interval such as `30s`, `5m`, or `2h`. - [JsonPropertyName("interval")] - public string Interval { get; set; } = string.Empty; + /// Catalogue identity retained from the bound candidate when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("catalogue")] + public InstallationCatalogueIdentity? Catalogue { get; set; } - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Original catalogue trust metadata, not a verification claim. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("catalogueTrust")] + public CatalogTrustSnapshot? CatalogueTrust { get; set; } - /// Whether the schedule should re-arm after each tick. Defaults to true. - [JsonPropertyName("recurring")] - public bool? Recurring { get; set; } + /// The configuration change for the selected alternative only. + [JsonPropertyName("configurationChange")] + public required McpPlanConfigurationChange ConfigurationChange { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + /// Complete effective remote configuration for final installation review. + /// Earlier private selection reviews and package choices omit this field. + /// The owned remote resource requires it before issuing confirmation. + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("effectiveConfiguration")] + public McpInstallationRemoteConfiguration? EffectiveConfiguration { get; set; } -/// Register a cron scheduled prompt. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddCronRequest -{ - /// 5-field cron expression. - [JsonPropertyName("cron")] - public string Cron { get; set; } = string.Empty; + /// Identity from the retained plan, not caller display text. + [JsonPropertyName("identity")] + public required McpPlanResourceIdentity Identity { get; set; } - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// Non-secret values supplied for this selected alternative. + [JsonPropertyName("inputs")] + public required IList Inputs { get; set; } - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Policy decision bound to this plan. + [JsonPropertyName("policy")] + public required McpPlanPolicyResult Policy { get; set; } - /// Whether the schedule should re-arm after each tick. Defaults to true. - [JsonPropertyName("recurring")] - public bool? Recurring { get; set; } + /// Original source identity and content commitment. + [JsonPropertyName("provenance")] + public required McpPlanProvenance Provenance { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Explicit reviewed backend selection; no backend is accessed when no secrets are supplied. + [JsonPropertyName("secretStorage")] + public required McpInstallationSecretStorage SecretStorage { get; set; } - /// IANA timezone for evaluating the cron expression. - [JsonPropertyName("tz")] - public string? Tz { get; set; } + /// Only the selected alternative is applied. + [JsonPropertyName("selectedChoice")] + public required McpPlanTransportChoice SelectedChoice { get; set; } + + /// Exact reviewed placeholders supplied separately. Never secret values. + [JsonPropertyName("suppliedSecrets")] + public required IList SuppliedSecrets { get; set; } + + /// Exact reviewed user-scope destination. + [JsonPropertyName("target")] + public required McpPlanTarget Target { get; set; } } -/// Register an absolute-time scheduled prompt. +/// The uninstall variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddAtRequest +public partial class McpInstallationReviewUninstall : McpInstallationReview { - /// Epoch milliseconds when the prompt should fire. - [JsonPropertyName("at")] - public long At { get; set; } + /// + [JsonIgnore] + public override string Action => "uninstall"; - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// Identity from the installed receipt. + [JsonPropertyName("identity")] + public required McpPlanResourceIdentity Identity { get; set; } - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Receipt-owned installation being removed. + [JsonPropertyName("installationId")] + public required string InstallationId { get; set; } - /// Whether the schedule should re-arm after each tick. Defaults to false. - [JsonPropertyName("recurring")] - public bool? Recurring { get; set; } + /// Exact planner-owned secret slots to remove, excluding shared OAuth grants. + [JsonPropertyName("ownedSecretCount")] + public required long OwnedSecretCount { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Current removal policy, independent of permission to activate the server. + [JsonPropertyName("policy")] + public required McpPlanPolicyResult Policy { get; set; } -/// Register a self-paced scheduled prompt. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddSelfPacedRequest -{ - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// Shared profile authentication is deliberately retained, not pending cleanup. + [JsonPropertyName("preservesSharedAuthentication")] + public required bool PreservesSharedAuthentication { get; set; } - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Source identity and content commitment retained by the installed receipt. + [JsonPropertyName("provenance")] + public required McpPlanProvenance Provenance { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether uninstall restores a protected pre-install configuration. + [JsonPropertyName("restoresPreviousConfiguration")] + public required bool RestoresPreviousConfiguration { get; set; } + + /// Exact destination, checked for intervening changes before mutation. + [JsonPropertyName("target")] + public required McpPlanTarget Target { get; set; } } -/// Re-arm a self-paced scheduled prompt. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleRearmSelfPacedRequest +public partial class InstallationReviewMcp : InstallationReview { - /// Epoch milliseconds when the prompt should next fire. - [JsonPropertyName("at")] - public long At { get; set; } - - /// Id of the self-paced scheduled prompt. - [JsonPropertyName("id")] - public long Id { get; set; } + /// + [JsonIgnore] + public override string Resource => "mcp"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The exact MCP action and its reviewed changes. + [JsonPropertyName("review")] + public required McpInstallationReview Review { get; set; } } -/// Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. +/// The skill variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ScheduleStopResult +public partial class InstallationReviewSkill : InstallationReview { - /// The removed entry, or omitted if no entry matched. - [JsonPropertyName("entry")] - public ScheduleEntry? Entry { get; set; } + /// + [JsonIgnore] + public override string Resource => "skill"; + + /// The exact verified Skill action and its reviewed files. + [JsonPropertyName("review")] + public required SkillInstallationReview Review { get; set; } } -/// Identifier of the scheduled prompt to remove. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleStopRequest +/// One connection-owned, expiring request for a trusted host's explicit user decision. +public sealed class InstallationsConfirmRequest { - /// Id of the scheduled prompt to remove. - [JsonPropertyName("id")] - public long Id { get; set; } + /// Opaque one-use challenge. Return unchanged; never log or persist. + [JsonPropertyName("confirmationId")] + public string ConfirmationId { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Original plan expiry as an ISO 8601 timestamp. Confirmation never extends it. + [JsonPropertyName("expiresAt")] + public string ExpiresAt { get; set; } = string.Empty; -/// A bearer token supplied by the SDK client for a BYOK provider. The runtime sets it as `Authorization: Bearer <token>` on the outbound request and does no caching; the SDK consumer owns token caching and refresh. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderTokenAcquireResult -{ - /// The bearer token value (without the `Bearer ` prefix). - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; -} + /// Random identifier of this installation operation, not a plan handle. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; -/// Asks the SDK client to acquire a bearer token for a BYOK provider whose config set `hasBearerTokenProvider: true`. Issued by the runtime before each outbound model request; the runtime does no caching, so this is sent once per request. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderTokenAcquireRequest -{ - /// Name of the BYOK provider needing a token. For the legacy whole-session provider this is the implicit provider name; for named providers it is the configured provider name. - [JsonPropertyName("providerName")] - public string ProviderName { get; set; } = string.Empty; + /// + /// Original engine-resolved selector for a bound operation, never a dispatch default. + /// Bound MCP confirmation always includes it; correlate it with the original pending action. + /// + [JsonPropertyName("policySessionId")] + public string? PolicySessionId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Resource-specific review to present before collecting the user's decision. + [JsonPropertyName("review")] + public InstallationReview Review { get => field ??= new(); set; } -/// Result returned by an extension workflow closure. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowExecuteResult -{ - /// Workflow result value. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + /// Opaque commitment to the exact review and inputs. Return unchanged; never log. + [JsonPropertyName("reviewFingerprint")] + public string ReviewFingerprint { get; set; } = string.Empty; } -/// Parameters sent to the owning extension to execute a workflow closure. +/// Closed set of public task kinds a connection can negotiate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowExecuteRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct TaskKind : IEquatable { - /// Workflow input value. - [JsonPropertyName("args")] - public JsonElement Args { get; set; } + private readonly string? _value; - /// Opaque token identifying this workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public TaskKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Registered workflow name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Runtime-owned background agent task. + public static TaskKind Agent { get; } = new("agent"); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Runtime-owned shell task. + public static TaskKind Shell { get; } = new("shell"); -/// Parameters for cooperatively aborting a workflow body. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAbortRequest -{ - /// Opaque token identifying the execution attempt to abort. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; + /// Client-owned externally executed task. + public static TaskKind Client { get; } = new("client"); - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(TaskKind left, TaskKind right) => left.Equals(right); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(TaskKind left, TaskKind right) => !(left == right); -/// Whether the client authoritatively confirmed its external work stopped. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ClientTaskCancelResult -{ - /// True only when the owner confirms that external work stopped before responding. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } -} + /// + public override bool Equals(object? obj) => obj is TaskKind other && Equals(other); -/// Runtime-to-owner cancellation request for a client-owned task. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ClientTaskCancelRequest -{ - /// Opaque identifier shared by coalesced cancellation callers. - [JsonPropertyName("cancellationId")] - public string CancellationId { get; set; } = string.Empty; + /// + public bool Equals(TaskKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Owner-scoped task key included for correlation. - [JsonPropertyName("clientTaskId")] - public string ClientTaskId { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Canonical runtime-generated task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// + public override string ToString() => Value; - /// Reason the runtime requests cancellation. - [JsonPropertyName("reason")] - public ClientTaskCancelReason Reason { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override TaskKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Session that owns the client task. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, TaskKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(TaskKind)); + } + } } -/// Describes a filesystem error. + +/// State of the persistent certificate authority of the sandbox credential proxy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsError +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SandboxProxyCaState : IEquatable { - /// Error classification. - [JsonPropertyName("code")] - public SessionFsErrorCode Code { get; set; } + private readonly string? _value; - /// Free-form detail about the error, for logging/diagnostics. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SandboxProxyCaState(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// For failed writeFile requests only: true if the provider changed the target before failing. Omit when unknown or unchanged. - [JsonPropertyName("writeChanged")] - public bool? WriteChanged { get; set; } -} + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; -/// File content as a UTF-8 string, or a filesystem error if the read failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileResult -{ - /// File content as UTF-8 string. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// This platform has no supported OS trust store. The proxy uses a per-process certificate bundle. + public static SandboxProxyCaState Unsupported { get; } = new("unsupported"); - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } -} + /// OS trust does not include the certificate authority, or none is stored. + public static SandboxProxyCaState NotInstalled { get; } = new("notInstalled"); -/// Path of the file to read from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// OS trust includes the stored certificate authority. + public static SandboxProxyCaState Installed { get; } = new("installed"); + + /// The runtime could not read the certificate authority or the OS trust store. + public static SandboxProxyCaState Error { get; } = new("error"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SandboxProxyCaState left, SandboxProxyCaState right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SandboxProxyCaState left, SandboxProxyCaState right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SandboxProxyCaState other && Equals(other); + + /// + public bool Equals(SandboxProxyCaState 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 SandboxProxyCaState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, SandboxProxyCaState value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SandboxProxyCaState)); + } + } } -/// File bytes as standard base64, or a filesystem error if the read failed. + +/// What the one-time staff update-channel migration did. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileBytesResult +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct StaffUpdateChannelMigrationStatus : IEquatable { - /// Exact file bytes encoded as standard base64. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + private readonly string? _value; - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public StaffUpdateChannelMigrationStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// Path of the binary file to read from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileBytesRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// The account is not a staff account, so the migration does not apply and nothing was recorded. + public static StaffUpdateChannelMigrationStatus Ineligible { get; } = new("ineligible"); -/// File path, content to write, and optional mode for the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsWriteFileRequest -{ - /// Content to write. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// The migration already ran within the cutoff window; the stored completion timestamp is returned unchanged. + public static StaffUpdateChannelMigrationStatus Current { get; } = new("current"); - /// Optional POSIX-style mode for newly created files. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// The persisted update channel was changed to stable. Only this outcome requires the host to reload its configuration. + public static StaffUpdateChannelMigrationStatus Migrated { get; } = new("migrated"); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// The persisted channel was already stable, so nothing changed, but the migration is now recorded as done. + public static StaffUpdateChannelMigrationStatus Completed { get; } = new("completed"); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// The account is on the experimental channel, which the migration deliberately leaves alone, and the migration is recorded as done. + public static StaffUpdateChannelMigrationStatus ExcludedExperimental { get; } = new("excluded-experimental"); -/// File path, standard-base64-encoded bytes to write, and optional mode for the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsWriteFileBytesRequest -{ - /// Exact file bytes encoded as standard base64. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(StaffUpdateChannelMigrationStatus left, StaffUpdateChannelMigrationStatus right) => left.Equals(right); - /// Optional POSIX-style mode for newly created files. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(StaffUpdateChannelMigrationStatus left, StaffUpdateChannelMigrationStatus right) => !(left == right); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is StaffUpdateChannelMigrationStatus other && Equals(other); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public bool Equals(StaffUpdateChannelMigrationStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// File path, content to append, and optional mode for the client-provided session filesystem. Implementations create parent directories as needed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsAppendFileRequest -{ - /// Content to append. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Optional POSIX-style mode for newly created files. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// + public override string ToString() => Value; - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override StaffUpdateChannelMigrationStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, StaffUpdateChannelMigrationStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(StaffUpdateChannelMigrationStatus)); + } + } } -/// Indicates whether the requested path exists in the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsExistsResult -{ - /// Whether the path exists. - [JsonPropertyName("exists")] - public bool Exists { get; set; } -} -/// Path to test for existence in the client-provided session filesystem. +/// What the one-time staff log-level migration did. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsExistsRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct StaffLogLevelMigrationStatus : IEquatable { - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + private readonly string? _value; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public StaffLogLevelMigrationStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// Filesystem metadata for the requested path, or a filesystem error if the stat failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsStatResult -{ - /// ISO 8601 timestamp of creation. - [JsonPropertyName("birthtime")] - public DateTimeOffset Birthtime { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } + /// The account is not a staff account, so the migration does not apply and nothing was recorded. + public static StaffLogLevelMigrationStatus Ineligible { get; } = new("ineligible"); - /// Whether the path is a directory. - [JsonPropertyName("isDirectory")] - public bool IsDirectory { get; set; } + /// The migration already ran; the stored completion timestamp is returned unchanged. + public static StaffLogLevelMigrationStatus Current { get; } = new("current"); - /// Whether the path is a file. - [JsonPropertyName("isFile")] - public bool IsFile { get; set; } + /// The migration ran now. The persisted settings may have changed, so the host should adopt the returned settings when they are present. + public static StaffLogLevelMigrationStatus Refreshed { get; } = new("refreshed"); - /// ISO 8601 timestamp of last modification. - [JsonPropertyName("mtime")] - public DateTimeOffset Mtime { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(StaffLogLevelMigrationStatus left, StaffLogLevelMigrationStatus right) => left.Equals(right); - /// File size in bytes. - [JsonPropertyName("size")] - public long Size { get; set; } -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(StaffLogLevelMigrationStatus left, StaffLogLevelMigrationStatus right) => !(left == right); -/// Path whose metadata should be returned from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsStatRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is StaffLogLevelMigrationStatus other && Equals(other); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public bool Equals(StaffLogLevelMigrationStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsMkdirRequest -{ - /// Optional POSIX-style mode for newly created directories. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override string ToString() => Value; - /// Create parent directories as needed. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override StaffLogLevelMigrationStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, StaffLogLevelMigrationStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(StaffLogLevelMigrationStatus)); + } + } } -/// Names of entries in the requested directory, or a filesystem error if the read failed. + +/// What the one-time obsolete-settings cleanup did to the document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirResult +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct UserSettingsMigrateObsoleteOnDiskStatus : IEquatable { - /// Entry names in the directory. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + private readonly string? _value; - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public UserSettingsMigrateObsoleteOnDiskStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// Directory path whose entries should be listed from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// No settings document exists, so there was nothing to clean. + public static UserSettingsMigrateObsoleteOnDiskStatus Missing { get; } = new("missing"); -/// Directory entry returned by session filesystem `readdirWithTypes`, with name and entry type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirWithTypesEntry -{ - /// Entry name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The document could not be parsed, so it was left untouched rather than rewritten from a partial read. + public static UserSettingsMigrateObsoleteOnDiskStatus Invalid { get; } = new("invalid"); - /// Entry type. - [JsonPropertyName("type")] - public SessionFsReaddirWithTypesEntryType Type { get; set; } -} + /// The document parsed and held nothing obsolete, so nothing was written. + public static UserSettingsMigrateObsoleteOnDiskStatus Unchanged { get; } = new("unchanged"); -/// Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirWithTypesResult -{ - /// Directory entries with type information. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + /// Obsolete keys were removed and the document was rewritten. + public static UserSettingsMigrateObsoleteOnDiskStatus Changed { get; } = new("changed"); - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } -} + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(UserSettingsMigrateObsoleteOnDiskStatus left, UserSettingsMigrateObsoleteOnDiskStatus right) => left.Equals(right); -/// Directory path whose entries (with type information) should be listed from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirWithTypesRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(UserSettingsMigrateObsoleteOnDiskStatus left, UserSettingsMigrateObsoleteOnDiskStatus right) => !(left == right); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public override bool Equals(object? obj) => obj is UserSettingsMigrateObsoleteOnDiskStatus other && Equals(other); -/// Path to remove from the client-provided session filesystem, with options for recursive removal and force. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsRmRequest -{ - /// Ignore errors if the path does not exist. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// + public bool Equals(UserSettingsMigrateObsoleteOnDiskStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Remove directories and their contents recursively. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } + /// + public override string ToString() => Value; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override UserSettingsMigrateObsoleteOnDiskStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, UserSettingsMigrateObsoleteOnDiskStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UserSettingsMigrateObsoleteOnDiskStatus)); + } + } } -/// Source and destination paths for renaming or moving an entry in the client-provided session filesystem. + +/// Whether one atomic settings edit changed a file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsRenameRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SettingsEditStatus : IEquatable { - /// Destination path using SessionFs conventions. - [JsonPropertyName("dest")] - public string Dest { get; set; } = string.Empty; + private readonly string? _value; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SettingsEditStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Source path using SessionFs conventions. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; -} + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; -/// Query results including rows, columns, and rows affected, or a filesystem error if execution failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteQueryResult -{ - /// Column names from the result set. - [JsonPropertyName("columns")] - public IList Columns { get => field ??= []; set; } + /// The edit changed the setting and was stored. + public static SettingsEditStatus Changed { get; } = new("changed"); - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } + /// The setting already had the requested state. + public static SettingsEditStatus Unchanged { get; } = new("unchanged"); - /// SQLite last_insert_rowid() value for INSERT. - [JsonPropertyName("lastInsertRowid")] - public long? LastInsertRowid { get; set; } + /// The existing settings file could not be edited safely; nothing was written. + public static SettingsEditStatus Invalid { get; } = new("invalid"); - /// For SELECT: array of row objects. For others: empty array. - [JsonPropertyName("rows")] - public IList> Rows { get => field ??= []; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SettingsEditStatus left, SettingsEditStatus right) => left.Equals(right); - /// Number of rows affected (for INSERT/UPDATE/DELETE). - [JsonPropertyName("rowsAffected")] - public long RowsAffected { get; set; } -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SettingsEditStatus left, SettingsEditStatus right) => !(left == right); -/// SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. The provider applies its SQLite busy timeout for every call. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteQueryRequest -{ - /// Optional named bind parameters. - [JsonPropertyName("params")] - public IDictionary? Params { get; set; } + /// + public override bool Equals(object? obj) => obj is SettingsEditStatus other && Equals(other); - /// SQL query to execute. - [JsonPropertyName("query")] - public string Query { get; set; } = string.Empty; + /// + public bool Equals(SettingsEditStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected). - [JsonPropertyName("queryType")] - public SessionFsSqliteQueryType QueryType { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public override string ToString() => Value; -/// Classified SQLite transaction failure. busyOrLocked guarantees rollback; postCommitAmbiguous must never be retried. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionError -{ - /// Machine-readable classification of the transaction failure. - [JsonPropertyName("errorClass")] - public SessionFsSqliteTransactionErrorClass ErrorClass { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SettingsEditStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Human-readable transaction failure message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, SettingsEditStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditStatus)); + } + } } -/// Per-statement results, or a classified transaction error. + +/// One atomic settings mutation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionResult +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SettingsEditOperation : IEquatable { - /// Classified transaction failure, when execution did not succeed. - [JsonPropertyName("error")] - public SessionFsSqliteTransactionError? Error { get; set; } + private readonly string? _value; - /// Per-statement query results in input order. - [JsonPropertyName("results")] - public IList Results { get => field ??= []; set; } -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SettingsEditOperation(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// One statement in an atomic SQLite transaction. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionStatement -{ - /// Optional named bind parameters. - [JsonPropertyName("params")] - public IDictionary? Params { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// SQL statement to execute. - [JsonPropertyName("query")] - public string Query { get; set; } = string.Empty; + /// Set one scalar value. + public static SettingsEditOperation Set { get; } = new("set"); - /// How to execute the statement. - [JsonPropertyName("queryType")] - public SessionFsSqliteQueryType QueryType { get; set; } -} + /// Add one string to a list, unless present. + public static SettingsEditOperation AddItem { get; } = new("add-item"); -/// Statements to execute atomically. Providers apply busy handling for every call. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Remove one string from a list, unless absent. + public static SettingsEditOperation RemoveItem { get; } = new("remove-item"); - /// Ordered SQL statements to execute in one transaction. - [JsonPropertyName("statements")] - public IList Statements { get => field ??= []; set; } -} + /// Remove the setting without supplying a value. + public static SettingsEditOperation Remove { get; } = new("remove"); -/// Indicates whether the per-session SQLite database already exists. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteExistsResult -{ - /// Whether the session database already exists. - [JsonPropertyName("exists")] - public bool Exists { get; set; } -} + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SettingsEditOperation left, SettingsEditOperation right) => left.Equals(right); -/// Identifies the target session. -public sealed class SessionFsSqliteExistsRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SettingsEditOperation left, SettingsEditOperation right) => !(left == right); -/// Canvas open result returned by the provider. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderOpenResult -{ - /// Provider-supplied status text. - [JsonPropertyName("status")] - public string? Status { get; set; } + /// + public override bool Equals(object? obj) => obj is SettingsEditOperation other && Equals(other); - /// Provider-supplied title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// + public bool Equals(SettingsEditOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// URL for web-rendered canvases. - [JsonPropertyName("url")] - public string? Url { get; set; } -} + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); -/// Host capabilities. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasHostContextCapabilities -{ - /// Whether canvas rendering is supported. - [JsonPropertyName("canvases")] - public bool? Canvases { get; set; } -} + /// + public override string ToString() => Value; -/// Host context supplied by the runtime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasHostContext -{ - /// Host capabilities. - [JsonPropertyName("capabilities")] - public CanvasHostContextCapabilities? Capabilities { get; set; } -} + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SettingsEditOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } -/// Session context supplied by the runtime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasSessionContext -{ - /// Active session working directory, when known. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// + public override void Write(Utf8JsonWriter writer, SettingsEditOperation value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditOperation)); + } + } } -/// Canvas open parameters sent to the provider. + +/// Which repository settings file to edit. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderOpenRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct RepoSettingsEditScope : IEquatable { - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; + private readonly string? _value; - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public RepoSettingsEditScope(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Host context supplied by the runtime. - [JsonPropertyName("host")] - public CanvasHostContext? Host { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Canvas open input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } + /// The shared repository settings file. + public static RepoSettingsEditScope Repo { get; } = new("repo"); - /// Stable caller-supplied canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// The local repository settings file. + public static RepoSettingsEditScope Local { get; } = new("local"); - /// Session context supplied by the runtime. - [JsonPropertyName("session")] - public CanvasSessionContext? Session { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(RepoSettingsEditScope left, RepoSettingsEditScope right) => left.Equals(right); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(RepoSettingsEditScope left, RepoSettingsEditScope right) => !(left == right); -/// Canvas close parameters sent to the provider. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderCloseRequest -{ - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is RepoSettingsEditScope other && Equals(other); - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// + public bool Equals(RepoSettingsEditScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Host context supplied by the runtime. - [JsonPropertyName("host")] - public CanvasHostContext? Host { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// + public override string ToString() => Value; - /// Session context supplied by the runtime. - [JsonPropertyName("session")] - public CanvasSessionContext? Session { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override RepoSettingsEditScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, RepoSettingsEditScope value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RepoSettingsEditScope)); + } + } } -/// Canvas action invocation parameters sent to the provider. + +/// The population a feature flag is declared for, before overrides. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderInvokeActionRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct FeatureFlagAvailability : IEquatable { - /// Action name to invoke. - [JsonPropertyName("actionName")] - public string ActionName { get; set; } = string.Empty; + private readonly string? _value; - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public FeatureFlagAvailability(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Host context supplied by the runtime. - [JsonPropertyName("host")] - public CanvasHostContext? Host { get; set; } + /// Enabled for everyone, before any override. + public static FeatureFlagAvailability On { get; } = new("on"); - /// Action input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } + /// Enabled only for accounts on the owning team. + public static FeatureFlagAvailability Team { get; } = new("team"); - /// Canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// Enabled only for staff accounts that have also opted into experimental features. + public static FeatureFlagAvailability StaffAndExperimental { get; } = new("staff-and-experimental"); - /// Session context supplied by the runtime. - [JsonPropertyName("session")] - public CanvasSessionContext? Session { get; set; } + /// Enabled for staff accounts and for accounts that opted into experimental features. + public static FeatureFlagAvailability StaffOrExperimental { get; } = new("staff-or-experimental"); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Enabled for any staff account, GitHub or Microsoft. + public static FeatureFlagAvailability Staff { get; } = new("staff"); -/// Reports a supervised listener's hosting-task termination and cleanup outcome. -public sealed class HostExitedRequest -{ - /// Explicit startup or teardown failure, when present. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Enabled for GitHub staff accounts only. + public static FeatureFlagAvailability StaffGitHub { get; } = new("staff-github"); - /// Process exit status when available; absent for in-process listener tasks. - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } + /// Enabled for Microsoft staff accounts only. + public static FeatureFlagAvailability StaffMicrosoft { get; } = new("staff-microsoft"); - /// Listener UUID. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; + /// Enabled only for accounts that opted into experimental features. + public static FeatureFlagAvailability Experimental { get; } = new("experimental"); - /// Cause of termination. - [JsonPropertyName("reason")] - public HostExitReason Reason { get; set; } -} + /// Disabled for everyone, before any override. + public static FeatureFlagAvailability Off { get; } = new("off"); -/// Opaque integrator-owned process launch profile for one extension entrypoint. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionLaunchProfile -{ - /// Opaque integrator-defined arguments passed to the executable. The runtime does not append the extension entrypoint. - [JsonPropertyName("args")] - public IList Args { get => field ??= []; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(FeatureFlagAvailability left, FeatureFlagAvailability right) => left.Equals(right); - /// Opaque integrator-defined environment variables. Runtime-owned COPILOT_SDK_PATH, SESSION_ID, and COPILOT_EXTENSION_PARENT_PID values take precedence. - [JsonPropertyName("env")] - public IDictionary Env { get => field ??= new Dictionary(); set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(FeatureFlagAvailability left, FeatureFlagAvailability right) => !(left == right); - /// Executable used to launch the extension entrypoint. - [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("executable")] - public string Executable { get; set; } = string.Empty; -} + /// + public override bool Equals(object? obj) => obj is FeatureFlagAvailability other && Equals(other); -/// The launch profile for a supported entrypoint. Omit launch when the provider does not support the entrypoint. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionLaunchProviderResolveResult -{ - /// Opaque launch profile, omitted when this provider does not support the entrypoint. - [JsonPropertyName("launch")] - public ExtensionLaunchProfile? Launch { get; set; } -} + /// + public bool Equals(FeatureFlagAvailability other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// A discovered extension entrypoint that the registered integrator may classify and resolve to an opaque launch profile. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionLaunchProviderResolveRequest -{ - /// Source-qualified extension identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Absolute path to the discovered extension entrypoint. - [JsonPropertyName("modulePath")] - public string ModulePath { get; set; } = string.Empty; + /// + public override string ToString() => Value; - /// Human-readable extension name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override FeatureFlagAvailability Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Discovery source for the extension entrypoint. - [JsonPropertyName("source")] - public ExtensionSource Source { get; set; } + /// + public override void Write(Utf8JsonWriter writer, FeatureFlagAvailability value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(FeatureFlagAvailability)); + } + } } -/// Acknowledgement. Returning successfully simply means the SDK accepted the start frame; it does not imply the request will succeed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestStartResult -{ -} -/// The head of an outbound model-layer HTTP request. +/// Which layer disabled bypass-permissions mode. The layer matters because only a server-delivered disable is pinned to an account and can later be lifted by signing in elsewhere. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestStartRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsBypassDisableSource : IEquatable { - /// Stable identity of the agent trajectory that issued this request. Present when the request originates from an agent turn; absent for requests outside any agent context. This is the same identity used by lifecycle and bridged session events and remains constant across turns and retries. - [JsonPropertyName("agentId")] - public string? AgentId { get; set; } + private readonly string? _value; - /// Identity of the agent invocation (one agentic loop) that issued this request. It remains fixed across physical retries within the invocation and is distinct from the stable trajectory `agentId`. A caller-supplied invocation id always takes precedence (this covers auxiliary calls that have no model call id). Otherwise, first-party CAPI requests fall back to the runtime's agent task id — the same value the runtime emits as the `X-Agent-Task-Id` header — while custom-provider requests fall back to the model call id. - [JsonPropertyName("agentInvocationId")] - public string? AgentInvocationId { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsBypassDisableSource(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// HTTP request headers, preserving multiple values per name. - [JsonPropertyName("headers")] - public IDictionary> Headers { get => field ??= new Dictionary>(); set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Coarse classification of the interaction that produced this request. Open string for forward-compatibility; known values include `conversation-agent`, `conversation-subagent`, `conversation-sampling`, `conversation-background`, `conversation-compaction`, and `conversation-user`. Absent when the runtime did not classify the request. Comes from the runtime's per-request agent context independently of transport; on the CAPI transport the runtime derives the upstream `X-Interaction-Type` header from this same context. - [JsonPropertyName("interactionType")] - public string? InteractionType { get; set; } + /// The user turned bypass mode off themselves. + public static ManagedSettingsBypassDisableSource User { get; } = new("user"); - /// HTTP method, e.g. GET, POST. - [JsonPropertyName("method")] - public string Method { get; set; } = string.Empty; + /// The account's server-delivered org policy disabled it. Pinned to the account named by `currentManagedIdentity`. + public static ManagedSettingsBypassDisableSource Managed { get; } = new("managed"); - /// Stable identity of the immediate parent trajectory. Present for child trajectories such as subagents and conversation-sampling requests; absent for root-agent and non-agent requests. - [JsonPropertyName("parentAgentId")] - public string? ParentAgentId { get; set; } + /// The device/MDM layer disabled it. Outranks the account, so no server answer lifts it. + public static ManagedSettingsBypassDisableSource Mdm { get; } = new("mdm"); - /// Opaque runtime-minted id, unique per in-flight request. The SDK uses this to correlate httpRequestChunk frames and to address its httpResponseStart / httpResponseChunk replies back to the runtime. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsBypassDisableSource left, ManagedSettingsBypassDisableSource right) => left.Equals(right); - /// Id of the runtime session that triggered this request, when one is in scope. Absent for requests issued outside any session (e.g. startup model-catalog or capability resolution). This is a payload field — not a dispatch key — because the client-global API is registered process-wide rather than per session. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsBypassDisableSource left, ManagedSettingsBypassDisableSource right) => !(left == right); - /// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. - [JsonPropertyName("transport")] - public LlmInferenceHttpRequestStartTransport? Transport { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsBypassDisableSource other && Equals(other); - /// Absolute request URL. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; -} + /// + public bool Equals(ManagedSettingsBypassDisableSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// Acknowledgement. The SDK is free to ignore the ack and treat chunk delivery as fire-and-forget. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestChunkResult -{ + /// + 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 ManagedSettingsBypassDisableSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsBypassDisableSource value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsBypassDisableSource)); + } + } } -/// A request body chunk or cancellation signal. + +/// What the managed-policy resolution said about bypass-permissions mode. `unknown` is a third answer rather than a missing one, and the caller must send it explicitly when it has no verdict. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestChunkRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsBypassPolicyResolution : IEquatable { - /// Identity of the agent invocation (one agentic loop) this body chunk belongs to, matching the `agentInvocationId` semantics on httpRequestStart. Carried per chunk so a persistent transport can attribute successive turns correctly: when a WebSocket connection is reused across turns, the httpRequestStart identity reflects only the turn that opened the connection, so each later turn stamps its own invocation id here. Absent when the runtime has no invocation context for the request, or on the plain-HTTP transport where every request has its own httpRequestStart. - [JsonPropertyName("agentInvocationId")] - public string? AgentInvocationId { get; set; } + private readonly string? _value; - /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. - [JsonPropertyName("binary")] - public bool? Binary { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsBypassPolicyResolution(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// When true, the runtime is cancelling the in-flight request (e.g. upstream consumer aborted). `data` is ignored. Implies end-of-request. - [JsonPropertyName("cancel")] - public bool? Cancel { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Optional human-readable reason for the cancellation, propagated for logging. - [JsonPropertyName("cancelReason")] - public string? CancelReason { get; set; } + /// The policy resolved and does not disable bypass mode. + public static ManagedSettingsBypassPolicyResolution Allowed { get; } = new("allowed"); - /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty. - [JsonPropertyName("data")] - public string Data { get; set; } = string.Empty; + /// The policy resolved and disables bypass mode. + public static ManagedSettingsBypassPolicyResolution Disabled { get; } = new("disabled"); - /// When true, this is the final body chunk for the request. The SDK may rely on having received an end-marked chunk before treating the request body as complete. - [JsonPropertyName("end")] - public bool? End { get; set; } + /// No verdict: the fetch failed, or the service declared a policy this build may not enforce. Whatever is in force is preserved, because reverting to permissive on an unreadable policy would widen access. + public static ManagedSettingsBypassPolicyResolution Unknown { get; } = new("unknown"); - /// Matches the requestId from the originating httpRequestStart frame. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsBypassPolicyResolution left, ManagedSettingsBypassPolicyResolution right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsBypassPolicyResolution left, ManagedSettingsBypassPolicyResolution right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedSettingsBypassPolicyResolution other && Equals(other); + + /// + public bool Equals(ManagedSettingsBypassPolicyResolution 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 ManagedSettingsBypassPolicyResolution Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsBypassPolicyResolution value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsBypassPolicyResolution)); + } + } } -/// Client environment metadata describing the process that produced a telemetry event. + +/// Severity of a diagnostic emitted while ingesting managed settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTelemetryClientInfo +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsLogLevel : IEquatable { - /// Copilot CLI version string. - [JsonPropertyName("cli_version")] - public string CliVersion { get; set; } = string.Empty; + private readonly string? _value; - /// Name of the client application. - [JsonPropertyName("client_name")] - public string? ClientName { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsLogLevel(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Type of client. - [JsonPropertyName("client_type")] - public string? ClientType { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Copilot subscription plan, when known. - [JsonPropertyName("copilot_plan")] - public string? CopilotPlan { get; set; } + /// Detail useful only when diagnosing an ingestion. + public static ManagedSettingsLogLevel Debug { get; } = new("debug"); - /// Number of logical CPU cores on the host. - [JsonPropertyName("cpu_count")] - public long? CpuCount { get; set; } + /// Ordinary progress worth surfacing under a verbose flag. + public static ManagedSettingsLogLevel Info { get; } = new("info"); - /// Distinct CPU model names for the host, comma-separated. - [JsonPropertyName("cpu_model")] - public string? CpuModel { get; set; } + /// A condition the operator should see but which did not stop the ingestion. + public static ManagedSettingsLogLevel Warning { get; } = new("warning"); - /// Stable machine identifier for the device. - [JsonPropertyName("dev_device_id")] - public string? DevDeviceId { get; set; } + /// A failure that changed the outcome of the ingestion. + public static ManagedSettingsLogLevel Error { get; } = new("error"); - /// Whether the user is a GitHub/Microsoft staff member. - [JsonPropertyName("is_staff")] - public bool? IsStaff { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsLogLevel left, ManagedSettingsLogLevel right) => left.Equals(right); - /// Node.js runtime version string. - [JsonPropertyName("node_version")] - public string NodeVersion { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsLogLevel left, ManagedSettingsLogLevel right) => !(left == right); - /// Operating system architecture (e.g. arm64, x64). - [JsonPropertyName("os_arch")] - public string OsArch { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is ManagedSettingsLogLevel other && Equals(other); - /// Operating system platform (e.g. darwin, linux, win32). - [JsonPropertyName("os_platform")] - public string OsPlatform { get; set; } = string.Empty; + /// + public bool Equals(ManagedSettingsLogLevel other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Operating system version string. - [JsonPropertyName("os_version")] - public string OsVersion { get; set; } = string.Empty; + /// + 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 ManagedSettingsLogLevel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsLogLevel value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsLogLevel)); + } + } } -/// A single telemetry event in the runtime's native GitHub-shaped telemetry format, forwarded verbatim to opted-in hosts. The `restricted` flag on the enclosing GitHubTelemetryNotification distinguishes standard from restricted events; the payload shape is identical for both. + +/// Which channel registered the policy helper that produced a helper layer. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTelemetryEvent +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsPolicyHelperAuthority : IEquatable { - /// Client environment metadata. - [JsonPropertyName("client")] - public GitHubTelemetryClientInfo? Client { get; set; } + private readonly string? _value; - /// Copilot tracking ID for user-level attribution. - [JsonPropertyName("copilot_tracking_id")] - public string? CopilotTrackingId { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsPolicyHelperAuthority(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Timestamp when the event was created (ISO 8601 format). - [JsonPropertyName("created_at")] - public string? CreatedAt { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Experiment assignment context. - [JsonPropertyName("exp_assignment_context")] - public string? ExpAssignmentContext { get; set; } + /// The helper was registered by the device (MDM or managed file) layer. + public static ManagedSettingsPolicyHelperAuthority Device { get; } = new("device"); - /// Feature flags enabled for this session, as a map from flag to value. - [JsonPropertyName("features")] - public IDictionary? Features { get; set; } + /// The helper was registered by the account's server-delivered policy. + public static ManagedSettingsPolicyHelperAuthority Server { get; } = new("server"); - /// Event type/kind (e.g. get_completion_with_tools_turn, tool_call_executed). - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsPolicyHelperAuthority left, ManagedSettingsPolicyHelperAuthority right) => left.Equals(right); - /// Numeric metrics as a map from key to value. - [JsonPropertyName("metrics")] - public IDictionary Metrics { get => field ??= new Dictionary(); set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsPolicyHelperAuthority left, ManagedSettingsPolicyHelperAuthority right) => !(left == right); - /// Reference to the model call that produced this event. - [JsonPropertyName("model_call_id")] - public string? ModelCallId { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsPolicyHelperAuthority other && Equals(other); - /// String-valued properties as a map from key to value. - [JsonPropertyName("properties")] - public IDictionary Properties { get => field ??= new Dictionary(); set; } + /// + public bool Equals(ManagedSettingsPolicyHelperAuthority other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Session identifier the event belongs to. - [JsonPropertyName("session_id")] - public string? SessionId { get; set; } -} + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); -/// Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry event the runtime forwards to a host connection that opted into telemetry forwarding during the `server.connect` handshake. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTelemetryNotification -{ - /// The telemetry event, in the runtime's native GitHub-shaped telemetry format. - [JsonPropertyName("event")] - public GitHubTelemetryEvent Event { get => field ??= new(); set; } + /// + public override string ToString() => Value; - /// Whether this is a restricted telemetry event (cli.restricted_telemetry). Hosts must route restricted events to first-party Microsoft stores only. - [JsonPropertyName("restricted")] - public bool Restricted { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsPolicyHelperAuthority Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Session the telemetry event belongs to, when it is session-scoped. Omitted for sessionless events (for example, `server.sendTelemetry` calls with no session id), which are still forwarded to opted-in connections. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsPolicyHelperAuthority value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsPolicyHelperAuthority)); + } + } } -/// SDK host response to a GitHub credential request. -/// Polymorphic base type discriminated by kind. + +/// How the server layer of an ingestion was resolved. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(GitHubTokenAcquireResultToken), "token")] -[JsonDerivedType(typeof(GitHubTokenAcquireResultCancelled), "cancelled")] -public partial class GitHubTokenAcquireResult +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsServerPolicyResolution : IEquatable { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + private readonly string? _value; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsServerPolicyResolution(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// The token variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class GitHubTokenAcquireResultToken : GitHubTokenAcquireResult -{ - /// - [JsonIgnore] - public override string Kind => "token"; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// GitHub access token acquired by the SDK host. - [JsonPropertyName("accessToken")] - public required string AccessToken { get; set; } + /// A live fetch succeeded. + public static ManagedSettingsServerPolicyResolution Live { get; } = new("live"); - /// Remaining token lifetime in seconds when callback execution completes. It must exceed the one-hour preflight refresh threshold. - [JsonPropertyName("expiresIn")] - public required long ExpiresIn { get; set; } + /// A recent cached entry was served without a live fetch. + public static ManagedSettingsServerPolicyResolution FreshCache { get; } = new("freshCache"); - /// OAuth token type. Defaults to bearer when omitted. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("tokenType")] - public string? TokenType { get; set; } -} + /// No cached policy or confirmed no-policy result exists. + public static ManagedSettingsServerPolicyResolution CacheMiss { get; } = new("cacheMiss"); -/// The cancelled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class GitHubTokenAcquireResultCancelled : GitHubTokenAcquireResult -{ - /// - [JsonIgnore] - public override string Kind => "cancelled"; -} + /// A live fetch failed and a cached entry was served in its place. + public static ManagedSettingsServerPolicyResolution FallbackCache { get; } = new("fallbackCache"); -/// Asks the SDK client to acquire a GitHub access token from an opaque callback registration. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTokenAcquireRequest -{ - /// Effective GitHub host for which the callback must return a token. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// No policy could be resolved and the host proceeds unmanaged. + public static ManagedSettingsServerPolicyResolution FailOpen { get; } = new("failOpen"); - /// Why the runtime is requesting a GitHub credential. - [JsonPropertyName("reason")] - public GitHubTokenAcquireReason Reason { get; set; } + /// No policy could be resolved and the host applies the fail-closed gates. + public static ManagedSettingsServerPolicyResolution FailClosed { get; } = new("failClosed"); - /// Opaque identifier generated by the SDK for this callback registration. - [JsonPropertyName("registrationId")] - public string RegistrationId { get; set; } = string.Empty; + /// No fetch was attempted because no usable token was available. + public static ManagedSettingsServerPolicyResolution SkippedNoToken { get; } = new("skippedNoToken"); - /// Session receiving the token. Absent only before a cloud session has been assigned its id. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } -} + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsServerPolicyResolution left, ManagedSettingsServerPolicyResolution right) => left.Equals(right); -/// A response is meaningful only on the connection and request that issued its challenge. -public sealed class InstallationsConfirmResult -{ - /// Exact challenge from the request. - [JsonPropertyName("confirmationId")] - public string ConfirmationId { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsServerPolicyResolution left, ManagedSettingsServerPolicyResolution right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedSettingsServerPolicyResolution other && Equals(other); + + /// + public bool Equals(ManagedSettingsServerPolicyResolution other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; - /// Fresh explicit user decision. There is no default. - [JsonPropertyName("decision")] - public InstallationDecision Decision { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsServerPolicyResolution Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Exact review commitment from the request. - [JsonPropertyName("reviewFingerprint")] - public string ReviewFingerprint { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsServerPolicyResolution value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsServerPolicyResolution)); + } + } } -/// Only resource kinds with an implemented installation engine have a review variant. -/// Polymorphic base type discriminated by resource. + +/// The operation that requires a policy-helper response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "resource", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(InstallationReviewMcp), "mcp")] -[JsonDerivedType(typeof(InstallationReviewSkill), "skill")] -public partial class InstallationReview +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsPolicyHelperReason : IEquatable { - /// The type discriminator. - [JsonPropertyName("resource")] - public virtual string Resource { get; set; } = string.Empty; -} + private readonly string? _value; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsPolicyHelperReason(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// Safe MCP review fields. No raw card, retrieval URL, plan handle or secret value. -/// Polymorphic base type discriminated by action. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "action", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationReviewInstall), "install")] -[JsonDerivedType(typeof(McpInstallationReviewUninstall), "uninstall")] -public partial class McpInstallationReview -{ - /// The type discriminator. - [JsonPropertyName("action")] - public virtual string Action { get; set; } = string.Empty; -} + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + /// Resolve policy for session startup. + public static ManagedSettingsPolicyHelperReason SessionStart { get; } = new("sessionStart"); -/// -/// Final remote configuration, not a template. The producer refuses external-value -/// expansion before presenting this review. Receipt-owned secrets appear only as -/// `${installation-secret:<id>}` references whose `<id>` matches a reviewed -/// `${secret:<id>}` placeholder; values are never included. -/// -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationRemoteConfiguration -{ - /// - /// Configured headers, excluding separately authorised OAuth tokens. Values may - /// contain owned secret references, never secret values. - /// - [JsonPropertyName("headers")] - public IDictionary Headers { get => field ??= new Dictionary(); set; } + /// Resolve policy before plugin activation. + public static ManagedSettingsPolicyHelperReason PluginActivation { get; } = new("pluginActivation"); - /// Configured tool selection, not permission to invoke those tools. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsPolicyHelperReason left, ManagedSettingsPolicyHelperReason right) => left.Equals(right); - /// Transport in the effective persisted remote configuration. - [JsonPropertyName("transport")] - public McpPlanRemoteTransport Transport { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsPolicyHelperReason left, ManagedSettingsPolicyHelperReason right) => !(left == right); - /// Exact resolved endpoint, without templates or secret placeholders. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is ManagedSettingsPolicyHelperReason other && Equals(other); + + /// + public bool Equals(ManagedSettingsPolicyHelperReason 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 ManagedSettingsPolicyHelperReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsPolicyHelperReason value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsPolicyHelperReason)); + } + } } -/// The install variant of . + +/// How an ingestion may use the on-disk server-policy cache. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationReviewInstall : McpInstallationReview +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsServerPolicyCacheMode : IEquatable { - /// - [JsonIgnore] - public override string Action => "install"; + private readonly string? _value; - /// Catalogue identity retained from the bound candidate when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("catalogue")] - public InstallationCatalogueIdentity? Catalogue { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsServerPolicyCacheMode(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Original catalogue trust metadata, not a verification claim. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("catalogueTrust")] - public CatalogTrustSnapshot? CatalogueTrust { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// The configuration change for the selected alternative only. - [JsonPropertyName("configurationChange")] - public required McpPlanConfigurationChange ConfigurationChange { get; set; } + /// Serve a recent cache entry before a live fetch. + public static ManagedSettingsServerPolicyCacheMode PreferFresh { get; } = new("preferFresh"); - /// - /// Complete effective remote configuration for final installation review. - /// Earlier private selection reviews and package choices omit this field. - /// The owned remote resource requires it before issuing confirmation. - /// - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("effectiveConfiguration")] - public McpInstallationRemoteConfiguration? EffectiveConfiguration { get; set; } + /// Read cached policy without a network request. + public static ManagedSettingsServerPolicyCacheMode CacheOnly { get; } = new("cacheOnly"); - /// Identity from the retained plan, not caller display text. - [JsonPropertyName("identity")] - public required McpPlanResourceIdentity Identity { get; set; } + /// Serve a cached entry only as a fallback after a failed live fetch. + public static ManagedSettingsServerPolicyCacheMode FallbackOnly { get; } = new("fallbackOnly"); - /// Non-secret values supplied for this selected alternative. - [JsonPropertyName("inputs")] - public required IList Inputs { get; set; } + /// Ignore the cache entirely and rely on the live fetch alone. + public static ManagedSettingsServerPolicyCacheMode Disabled { get; } = new("disabled"); - /// Policy decision bound to this plan. - [JsonPropertyName("policy")] - public required McpPlanPolicyResult Policy { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsServerPolicyCacheMode left, ManagedSettingsServerPolicyCacheMode right) => left.Equals(right); - /// Original source identity and content commitment. - [JsonPropertyName("provenance")] - public required McpPlanProvenance Provenance { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsServerPolicyCacheMode left, ManagedSettingsServerPolicyCacheMode right) => !(left == right); - /// Explicit reviewed backend selection; no backend is accessed when no secrets are supplied. - [JsonPropertyName("secretStorage")] - public required McpInstallationSecretStorage SecretStorage { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsServerPolicyCacheMode other && Equals(other); - /// Only the selected alternative is applied. - [JsonPropertyName("selectedChoice")] - public required McpPlanTransportChoice SelectedChoice { get; set; } + /// + public bool Equals(ManagedSettingsServerPolicyCacheMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Exact reviewed placeholders supplied separately. Never secret values. - [JsonPropertyName("suppliedSecrets")] - public required IList SuppliedSecrets { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Exact reviewed user-scope destination. - [JsonPropertyName("target")] - public required McpPlanTarget Target { get; set; } + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsServerPolicyCacheMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsServerPolicyCacheMode value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsServerPolicyCacheMode)); + } + } } -/// The uninstall variant of . + +/// Severity of a managed-settings validation finding. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationReviewUninstall : McpInstallationReview +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsDiagnosticSeverity : IEquatable { - /// - [JsonIgnore] - public override string Action => "uninstall"; + private readonly string? _value; - /// Identity from the installed receipt. - [JsonPropertyName("identity")] - public required McpPlanResourceIdentity Identity { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsDiagnosticSeverity(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Receipt-owned installation being removed. - [JsonPropertyName("installationId")] - public required string InstallationId { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Exact planner-owned secret slots to remove, excluding shared OAuth grants. - [JsonPropertyName("ownedSecretCount")] - public required long OwnedSecretCount { get; set; } + /// The runtime rejects the document. + public static ManagedSettingsDiagnosticSeverity Error { get; } = new("error"); - /// Current removal policy, independent of permission to activate the server. - [JsonPropertyName("policy")] - public required McpPlanPolicyResult Policy { get; set; } + /// The runtime accepts the document but ignores the flagged content. + public static ManagedSettingsDiagnosticSeverity Warning { get; } = new("warning"); - /// Shared profile authentication is deliberately retained, not pending cleanup. - [JsonPropertyName("preservesSharedAuthentication")] - public required bool PreservesSharedAuthentication { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => left.Equals(right); - /// Source identity and content commitment retained by the installed receipt. - [JsonPropertyName("provenance")] - public required McpPlanProvenance Provenance { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => !(left == right); - /// Whether uninstall restores a protected pre-install configuration. - [JsonPropertyName("restoresPreviousConfiguration")] - public required bool RestoresPreviousConfiguration { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsDiagnosticSeverity other && Equals(other); - /// Exact destination, checked for intervening changes before mutation. - [JsonPropertyName("target")] - public required McpPlanTarget Target { get; set; } -} + /// + public bool Equals(ManagedSettingsDiagnosticSeverity other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// The mcp variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class InstallationReviewMcp : InstallationReview -{ /// - [JsonIgnore] - public override string Resource => "mcp"; + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// The exact MCP action and its reviewed changes. - [JsonPropertyName("review")] - public required McpInstallationReview Review { get; set; } + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsDiagnosticSeverity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsDiagnosticSeverity value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsDiagnosticSeverity)); + } + } } -/// The skill variant of . + +/// A channel accepted by managedSettings.compose. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class InstallationReviewSkill : InstallationReview +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsChannel : IEquatable { - /// - [JsonIgnore] - public override string Resource => "skill"; + private readonly string? _value; - /// The exact verified Skill action and its reviewed files. - [JsonPropertyName("review")] - public required SkillInstallationReview Review { get; set; } -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsChannel(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// One connection-owned, expiring request for a trusted host's explicit user decision. -public sealed class InstallationsConfirmRequest -{ - /// Opaque one-use challenge. Return unchanged; never log or persist. - [JsonPropertyName("confirmationId")] - public string ConfirmationId { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Original plan expiry as an ISO 8601 timestamp. Confirmation never extends it. - [JsonPropertyName("expiresAt")] - public string ExpiresAt { get; set; } = string.Empty; + /// Device policy, the strongest channel. + public static ManagedSettingsChannel Device { get; } = new("device"); - /// Random identifier of this installation operation, not a plan handle. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Account or organization policy. + public static ManagedSettingsChannel Server { get; } = new("server"); - /// - /// Original engine-resolved selector for a bound operation, never a dispatch default. - /// Bound MCP confirmation always includes it; correlate it with the original pending action. - /// - [JsonPropertyName("policySessionId")] - public string? PolicySessionId { get; set; } + /// Session-local helper output, the weakest channel. + public static ManagedSettingsChannel PolicyHelper { get; } = new("policyHelper"); - /// Resource-specific review to present before collecting the user's decision. - [JsonPropertyName("review")] - public InstallationReview Review { get => field ??= new(); set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsChannel left, ManagedSettingsChannel right) => left.Equals(right); - /// Opaque commitment to the exact review and inputs. Return unchanged; never log. - [JsonPropertyName("reviewFingerprint")] - public string ReviewFingerprint { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsChannel left, ManagedSettingsChannel right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedSettingsChannel other && Equals(other); + + /// + public bool Equals(ManagedSettingsChannel 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 ManagedSettingsChannel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsChannel value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsChannel)); + } + } } -/// Closed set of public task kinds a connection can negotiate. + +/// Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct TaskKind : IEquatable +public readonly struct ManagedPermissionVerdict : 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 TaskKind(string value) + public ManagedPermissionVerdict(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; - /// Runtime-owned background agent task. - public static TaskKind Agent { get; } = new("agent"); + /// Managed policy prohibits the operation; do not offer approval. + public static ManagedPermissionVerdict Deny { get; } = new("deny"); - /// Runtime-owned shell task. - public static TaskKind Shell { get; } = new("shell"); + /// Managed policy requires the consumer to obtain approval. + public static ManagedPermissionVerdict Ask { get; } = new("ask"); - /// Client-owned externally executed task. - public static TaskKind Client { get; } = new("client"); + /// Managed policy allows the operation, subject to other security controls. + public static ManagedPermissionVerdict Allow { get; } = new("allow"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(TaskKind left, TaskKind right) => left.Equals(right); + /// Managed policy does not decide the operation; use the consumer's normal permission flow. + public static ManagedPermissionVerdict Unmanaged { get; } = new("unmanaged"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(TaskKind left, TaskKind right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => !(left == right); /// - public override bool Equals(object? obj) => obj is TaskKind other && Equals(other); + public override bool Equals(object? obj) => obj is ManagedPermissionVerdict other && Equals(other); /// - public bool Equals(TaskKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ManagedPermissionVerdict other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -26704,20 +31377,20 @@ public TaskKind(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 TaskKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ManagedPermissionVerdict Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, TaskKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ManagedPermissionVerdict value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(TaskKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedPermissionVerdict)); } } } @@ -27242,43 +31915,64 @@ public override void Write(Utf8JsonWriter writer, ModelPolicyState value, JsonSe } -/// The neutral kind of a model provider — the model analog of `AccountKind`. A model provider is the live, entitled source a model came from; central code never branches on this beyond a single dispatch. +/// Authentication type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ModelProviderKind : IEquatable +public readonly struct AuthInfoType : 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 ModelProviderKind(string value) + public AuthInfoType(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 Copilot / CAPI models, spawned by a github-resolving account that holds a Copilot seat. - public static ModelProviderKind Copilot { get; } = new("copilot"); + /// Authentication provided by a GitHub App HMAC credential. + public static AuthInfoType Hmac { get; } = new("hmac"); + + /// Authentication resolved from environment-provided credentials. + public static AuthInfoType Env { get; } = new("env"); + + /// Authentication from an interactive user sign-in. + public static AuthInfoType User { get; } = new("user"); + + /// Authentication from a selected provider-owned account, without a GitHub credential. + public static AuthInfoType Account { get; } = new("account"); + + /// Authentication delegated to the GitHub CLI. + public static AuthInfoType GhCli { get; } = new("gh-cli"); + + /// Authentication from an API key credential. + public static AuthInfoType ApiKey { get; } = new("api-key"); + + /// Authentication from a GitHub token. + public static AuthInfoType Token { get; } = new("token"); + + /// Authentication from an SDK GitHub token callback. + public static AuthInfoType TokenProvider { get; } = new("token-provider"); - /// Microsoft 365 Copilot (Loki) inference models, spawned by a resolvable Entra-derived Loki account. - public static ModelProviderKind Loki { get; } = new("loki"); + /// Authentication from a Copilot API token. + public static AuthInfoType CopilotApiToken { get; } = new("copilot-api-token"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ModelProviderKind left, ModelProviderKind right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(AuthInfoType left, AuthInfoType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ModelProviderKind left, ModelProviderKind right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(AuthInfoType left, AuthInfoType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ModelProviderKind other && Equals(other); + public override bool Equals(object? obj) => obj is AuthInfoType other && Equals(other); /// - public bool Equals(ModelProviderKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(AuthInfoType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -27286,68 +31980,68 @@ public ModelProviderKind(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 ModelProviderKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override AuthInfoType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ModelProviderKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, AuthInfoType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelProviderKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AuthInfoType)); } } } -/// State of the persistent certificate authority of the sandbox credential proxy. +/// Server transport type: stdio, http, sse (deprecated), or memory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SandboxProxyCaState : IEquatable +public readonly struct DiscoveredMcpServerType : 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 SandboxProxyCaState(string value) + public DiscoveredMcpServerType(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; - /// This platform has no supported OS trust store. The proxy uses a per-process certificate bundle. - public static SandboxProxyCaState Unsupported { get; } = new("unsupported"); + /// Server communicates over stdio with a local child process. + public static DiscoveredMcpServerType Stdio { get; } = new("stdio"); - /// OS trust does not include the certificate authority, or none is stored. - public static SandboxProxyCaState NotInstalled { get; } = new("notInstalled"); + /// Server communicates over streamable HTTP. + public static DiscoveredMcpServerType Http { get; } = new("http"); - /// OS trust includes the stored certificate authority. - public static SandboxProxyCaState Installed { get; } = new("installed"); + /// Server communicates over Server-Sent Events (deprecated). + public static DiscoveredMcpServerType Sse { get; } = new("sse"); - /// The runtime could not read the certificate authority or the OS trust store. - public static SandboxProxyCaState Error { get; } = new("error"); + /// Server is backed by an in-memory runtime implementation. + public static DiscoveredMcpServerType Memory { get; } = new("memory"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SandboxProxyCaState left, SandboxProxyCaState right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(DiscoveredMcpServerType left, DiscoveredMcpServerType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SandboxProxyCaState left, SandboxProxyCaState right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(DiscoveredMcpServerType left, DiscoveredMcpServerType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SandboxProxyCaState other && Equals(other); + public override bool Equals(object? obj) => obj is DiscoveredMcpServerType other && Equals(other); /// - public bool Equals(SandboxProxyCaState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(DiscoveredMcpServerType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -27355,68 +32049,62 @@ public SandboxProxyCaState(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 SandboxProxyCaState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override DiscoveredMcpServerType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SandboxProxyCaState value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, DiscoveredMcpServerType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SandboxProxyCaState)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(DiscoveredMcpServerType)); } } } -/// Server transport type: stdio, http, sse (deprecated), or memory. +/// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct DiscoveredMcpServerType : IEquatable +public readonly struct OptionsUpdateToolFilterPrecedence : 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 DiscoveredMcpServerType(string value) + public OptionsUpdateToolFilterPrecedence(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; - /// Server communicates over stdio with a local child process. - public static DiscoveredMcpServerType Stdio { get; } = new("stdio"); - - /// Server communicates over streamable HTTP. - public static DiscoveredMcpServerType Http { get; } = new("http"); - - /// Server communicates over Server-Sent Events (deprecated). - public static DiscoveredMcpServerType Sse { get; } = new("sse"); + /// If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. + public static OptionsUpdateToolFilterPrecedence Available { get; } = new("available"); - /// Server is backed by an in-memory runtime implementation. - public static DiscoveredMcpServerType Memory { get; } = new("memory"); + /// A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. + public static OptionsUpdateToolFilterPrecedence Excluded { get; } = new("excluded"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(DiscoveredMcpServerType left, DiscoveredMcpServerType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(DiscoveredMcpServerType left, DiscoveredMcpServerType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => !(left == right); /// - public override bool Equals(object? obj) => obj is DiscoveredMcpServerType other && Equals(other); + public override bool Equals(object? obj) => obj is OptionsUpdateToolFilterPrecedence other && Equals(other); /// - public bool Equals(DiscoveredMcpServerType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(OptionsUpdateToolFilterPrecedence other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -27424,20 +32112,20 @@ public DiscoveredMcpServerType(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 DiscoveredMcpServerType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override OptionsUpdateToolFilterPrecedence Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, DiscoveredMcpServerType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, OptionsUpdateToolFilterPrecedence value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(DiscoveredMcpServerType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(OptionsUpdateToolFilterPrecedence)); } } } @@ -29837,6 +34525,285 @@ public override void Write(Utf8JsonWriter writer, DiscoveredExtensionMode value, } +/// Where this source lives — used for UI grouping. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionSourceLocation : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionSourceLocation(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Instructions live in user-level configuration. + public static InstructionSourceLocation User { get; } = new("user"); + + /// Instructions live in repository-level configuration. + public static InstructionSourceLocation Repository { get; } = new("repository"); + + /// Instructions live under the current working directory. + public static InstructionSourceLocation WorkingDirectory { get; } = new("working-directory"); + + /// Instructions live in plugin-provided configuration. + public static InstructionSourceLocation Plugin { get; } = new("plugin"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionSourceLocation left, InstructionSourceLocation right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionSourceLocation left, InstructionSourceLocation right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionSourceLocation other && Equals(other); + + /// + public bool Equals(InstructionSourceLocation 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 InstructionSourceLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionSourceLocation value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceLocation)); + } + } +} + + +/// Category of instruction source — used for merge logic. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionSourceType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionSourceType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Instructions loaded from the user's home configuration. + public static InstructionSourceType Home { get; } = new("home"); + + /// Instructions loaded from repository-scoped files. + public static InstructionSourceType Repo { get; } = new("repo"); + + /// Instructions loaded from model-specific files. + public static InstructionSourceType Model { get; } = new("model"); + + /// Instructions loaded from VS Code instruction files. + public static InstructionSourceType Vscode { get; } = new("vscode"); + + /// Instructions discovered from nested agent files. + public static InstructionSourceType NestedAgents { get; } = new("nested-agents"); + + /// Instructions inherited from child instruction files. + public static InstructionSourceType ChildInstructions { get; } = new("child-instructions"); + + /// Instructions supplied by an installed plugin. + public static InstructionSourceType Plugin { get; } = new("plugin"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionSourceType left, InstructionSourceType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionSourceType left, InstructionSourceType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionSourceType other && Equals(other); + + /// + public bool Equals(InstructionSourceType 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 InstructionSourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionSourceType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceType)); + } + } +} + + +/// Whether the target is a single file or a directory of instruction files. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionDiscoveryPathKind : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionDiscoveryPathKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The target is a single instruction file. + public static InstructionDiscoveryPathKind File { get; } = new("file"); + + /// The target is a directory that holds instruction files. + public static InstructionDiscoveryPathKind Directory { get; } = new("directory"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionDiscoveryPathKind other && Equals(other); + + /// + public bool Equals(InstructionDiscoveryPathKind 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 InstructionDiscoveryPathKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathKind)); + } + } +} + + +/// Which tier this target belongs to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionDiscoveryPathLocation : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionDiscoveryPathLocation(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Instructions live in user-level configuration. + public static InstructionDiscoveryPathLocation User { get; } = new("user"); + + /// Instructions live in repository-level configuration. + public static InstructionDiscoveryPathLocation Repository { get; } = new("repository"); + + /// Instructions live under the current working directory. + public static InstructionDiscoveryPathLocation WorkingDirectory { get; } = new("working-directory"); + + /// Instructions live in plugin-provided configuration. + public static InstructionDiscoveryPathLocation Plugin { get; } = new("plugin"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionDiscoveryPathLocation other && Equals(other); + + /// + public bool Equals(InstructionDiscoveryPathLocation 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 InstructionDiscoveryPathLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathLocation value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathLocation)); + } + } +} + + /// Defines the allowed values. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -30965,285 +35932,6 @@ public override void Write(Utf8JsonWriter writer, AgentDiscoveryPathScope value, } -/// Where this source lives — used for UI grouping. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionSourceLocation : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public InstructionSourceLocation(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Instructions live in user-level configuration. - public static InstructionSourceLocation User { get; } = new("user"); - - /// Instructions live in repository-level configuration. - public static InstructionSourceLocation Repository { get; } = new("repository"); - - /// Instructions live under the current working directory. - public static InstructionSourceLocation WorkingDirectory { get; } = new("working-directory"); - - /// Instructions live in plugin-provided configuration. - public static InstructionSourceLocation Plugin { get; } = new("plugin"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionSourceLocation left, InstructionSourceLocation right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionSourceLocation left, InstructionSourceLocation right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is InstructionSourceLocation other && Equals(other); - - /// - public bool Equals(InstructionSourceLocation 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 InstructionSourceLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, InstructionSourceLocation value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceLocation)); - } - } -} - - -/// Category of instruction source — used for merge logic. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionSourceType : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public InstructionSourceType(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Instructions loaded from the user's home configuration. - public static InstructionSourceType Home { get; } = new("home"); - - /// Instructions loaded from repository-scoped files. - public static InstructionSourceType Repo { get; } = new("repo"); - - /// Instructions loaded from model-specific files. - public static InstructionSourceType Model { get; } = new("model"); - - /// Instructions loaded from VS Code instruction files. - public static InstructionSourceType Vscode { get; } = new("vscode"); - - /// Instructions discovered from nested agent files. - public static InstructionSourceType NestedAgents { get; } = new("nested-agents"); - - /// Instructions inherited from child instruction files. - public static InstructionSourceType ChildInstructions { get; } = new("child-instructions"); - - /// Instructions supplied by an installed plugin. - public static InstructionSourceType Plugin { get; } = new("plugin"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionSourceType left, InstructionSourceType right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionSourceType left, InstructionSourceType right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is InstructionSourceType other && Equals(other); - - /// - public bool Equals(InstructionSourceType 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 InstructionSourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, InstructionSourceType value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceType)); - } - } -} - - -/// Whether the target is a single file or a directory of instruction files. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionDiscoveryPathKind : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public InstructionDiscoveryPathKind(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The target is a single instruction file. - public static InstructionDiscoveryPathKind File { get; } = new("file"); - - /// The target is a directory that holds instruction files. - public static InstructionDiscoveryPathKind Directory { get; } = new("directory"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is InstructionDiscoveryPathKind other && Equals(other); - - /// - public bool Equals(InstructionDiscoveryPathKind 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 InstructionDiscoveryPathKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathKind value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathKind)); - } - } -} - - -/// Which tier this target belongs to. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionDiscoveryPathLocation : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public InstructionDiscoveryPathLocation(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Instructions live in user-level configuration. - public static InstructionDiscoveryPathLocation User { get; } = new("user"); - - /// Instructions live in repository-level configuration. - public static InstructionDiscoveryPathLocation Repository { get; } = new("repository"); - - /// Instructions live under the current working directory. - public static InstructionDiscoveryPathLocation WorkingDirectory { get; } = new("working-directory"); - - /// Instructions live in plugin-provided configuration. - public static InstructionDiscoveryPathLocation Plugin { get; } = new("plugin"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is InstructionDiscoveryPathLocation other && Equals(other); - - /// - public bool Equals(InstructionDiscoveryPathLocation 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 InstructionDiscoveryPathLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathLocation value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathLocation)); - } - } -} - - /// Optional completion hint for the input (e.g. 'directory' for filesystem path completion). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -31370,109 +36058,43 @@ public override void Write(Utf8JsonWriter writer, SlashCommandKind value, JsonSe } -/// Severity of a managed-settings validation finding. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct ManagedSettingsDiagnosticSeverity : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public ManagedSettingsDiagnosticSeverity(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The runtime rejects the document. - public static ManagedSettingsDiagnosticSeverity Error { get; } = new("error"); - - /// The runtime accepts the document but ignores the flagged content. - public static ManagedSettingsDiagnosticSeverity Warning { get; } = new("warning"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is ManagedSettingsDiagnosticSeverity other && Equals(other); - - /// - public bool Equals(ManagedSettingsDiagnosticSeverity 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 ManagedSettingsDiagnosticSeverity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, ManagedSettingsDiagnosticSeverity value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsDiagnosticSeverity)); - } - } -} - - -/// A channel accepted by managedSettings.compose. +/// Hosting platform type of the repository. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ManagedSettingsChannel : IEquatable +public readonly struct SessionWorkingDirectoryContextHostType : 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 ManagedSettingsChannel(string value) + public SessionWorkingDirectoryContextHostType(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; - /// Device policy, the strongest channel. - public static ManagedSettingsChannel Device { get; } = new("device"); - - /// Account or organization policy. - public static ManagedSettingsChannel Server { get; } = new("server"); + /// The working directory repository is hosted on GitHub. + public static SessionWorkingDirectoryContextHostType GitHub { get; } = new("github"); - /// Session-local helper output, the weakest channel. - public static ManagedSettingsChannel PolicyHelper { get; } = new("policyHelper"); + /// The working directory repository is hosted on Azure DevOps. + public static SessionWorkingDirectoryContextHostType Ado { get; } = new("ado"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ManagedSettingsChannel left, ManagedSettingsChannel right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionWorkingDirectoryContextHostType left, SessionWorkingDirectoryContextHostType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ManagedSettingsChannel left, ManagedSettingsChannel right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionWorkingDirectoryContextHostType left, SessionWorkingDirectoryContextHostType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ManagedSettingsChannel other && Equals(other); + public override bool Equals(object? obj) => obj is SessionWorkingDirectoryContextHostType other && Equals(other); /// - public bool Equals(ManagedSettingsChannel other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionWorkingDirectoryContextHostType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -31480,20 +36102,20 @@ public ManagedSettingsChannel(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 ManagedSettingsChannel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionWorkingDirectoryContextHostType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ManagedSettingsChannel value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionWorkingDirectoryContextHostType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsChannel)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionWorkingDirectoryContextHostType)); } } } @@ -32765,6 +37387,144 @@ public override void Write(Utf8JsonWriter writer, AgentRegistrySpawnPermissionMo } +/// Availability. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ConnectorDiscoveryAvailability : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ConnectorDiscoveryAvailability(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Enabled. + public static ConnectorDiscoveryAvailability Enabled { get; } = new("enabled"); + + /// Disabled. + public static ConnectorDiscoveryAvailability Disabled { get; } = new("disabled"); + + /// Unavailable. + public static ConnectorDiscoveryAvailability Unavailable { get; } = new("unavailable"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ConnectorDiscoveryAvailability left, ConnectorDiscoveryAvailability right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ConnectorDiscoveryAvailability left, ConnectorDiscoveryAvailability right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ConnectorDiscoveryAvailability other && Equals(other); + + /// + public bool Equals(ConnectorDiscoveryAvailability 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 ConnectorDiscoveryAvailability Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ConnectorDiscoveryAvailability value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ConnectorDiscoveryAvailability)); + } + } +} + + +/// Authoritative service connection state for one Connector. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ConnectorCatalogStatus : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ConnectorCatalogStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The Connector is available but not connected. + public static ConnectorCatalogStatus NotConnected { get; } = new("not_connected"); + + /// The Connector service is still completing connection or consent. + public static ConnectorCatalogStatus Pending { get; } = new("pending"); + + /// The Connector is connected and may contribute MCP servers. + public static ConnectorCatalogStatus Connected { get; } = new("connected"); + + /// The Connector service reports an unusable connection. + public static ConnectorCatalogStatus Error { get; } = new("error"); + + /// The service returned a future or unrecognized state. + public static ConnectorCatalogStatus Unknown { get; } = new("unknown"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ConnectorCatalogStatus left, ConnectorCatalogStatus right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ConnectorCatalogStatus left, ConnectorCatalogStatus right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ConnectorCatalogStatus other && Equals(other); + + /// + public bool Equals(ConnectorCatalogStatus 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 ConnectorCatalogStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ConnectorCatalogStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ConnectorCatalogStatus)); + } + } +} + + /// The UI mode the agent was in when this message was sent. Defaults to the session's current mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -34217,87 +38977,6 @@ public override void Write(Utf8JsonWriter writer, PermissionDecisionSurface valu } -/// Authentication type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct AuthInfoType : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public AuthInfoType(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Authentication provided by a GitHub App HMAC credential. - public static AuthInfoType Hmac { get; } = new("hmac"); - - /// Authentication resolved from environment-provided credentials. - public static AuthInfoType Env { get; } = new("env"); - - /// Authentication from an interactive user sign-in. - public static AuthInfoType User { get; } = new("user"); - - /// Authentication delegated to the GitHub CLI. - public static AuthInfoType GhCli { get; } = new("gh-cli"); - - /// Authentication from an API key credential. - public static AuthInfoType ApiKey { get; } = new("api-key"); - - /// Authentication from a GitHub token. - public static AuthInfoType Token { get; } = new("token"); - - /// Authentication from an SDK GitHub token callback. - public static AuthInfoType TokenProvider { get; } = new("token-provider"); - - /// Authentication from a Copilot API token. - public static AuthInfoType CopilotApiToken { get; } = new("copilot-api-token"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(AuthInfoType left, AuthInfoType right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(AuthInfoType left, AuthInfoType right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is AuthInfoType other && Equals(other); - - /// - public bool Equals(AuthInfoType 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 AuthInfoType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, AuthInfoType value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AuthInfoType)); - } - } -} - - /// The provider kind stamped on a signed-in account. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -34436,7 +39115,7 @@ public override void Write(Utf8JsonWriter writer, LoginProviderKind value, JsonS } -/// Terminal disposition of a login persistence attempt. +/// Disposition of a login attempt, including pending user decisions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] @@ -34456,12 +39135,15 @@ public AuthLoginResultStatus(string value) /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// The credential was persisted and the account is signed in. + /// The credential was persisted and the selected account is signed in. public static AuthLoginResultStatus Completed { get; } = new("completed"); /// Persistence needs explicit consent to store the token in plaintext. public static AuthLoginResultStatus NeedsPlaintextConsent { get; } = new("needs-plaintext-consent"); + /// Credentials are saved; select an account using a returned selectionId as advance input to complete sign-in. + public static AuthLoginResultStatus NeedsAccountSelection { get; } = new("needs-account-selection"); + /// The user declined plaintext persistence. public static AuthLoginResultStatus Declined { get; } = new("declined"); @@ -37777,86 +42459,14 @@ public ConnectorAuthorizationScope(string value) /// Returns a value indicating whether two instances are equivalent. public static bool operator ==(ConnectorAuthorizationScope left, ConnectorAuthorizationScope right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ConnectorAuthorizationScope left, ConnectorAuthorizationScope right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is ConnectorAuthorizationScope other && Equals(other); - - /// - public bool Equals(ConnectorAuthorizationScope 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 ConnectorAuthorizationScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, ConnectorAuthorizationScope value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ConnectorAuthorizationScope)); - } - } -} - - -/// Authoritative service connection state for one Connector. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct ConnectorCatalogStatus : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public ConnectorCatalogStatus(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The Connector is available but not connected. - public static ConnectorCatalogStatus NotConnected { get; } = new("not_connected"); - - /// The Connector service is still completing connection or consent. - public static ConnectorCatalogStatus Pending { get; } = new("pending"); - - /// The Connector is connected and may contribute MCP servers. - public static ConnectorCatalogStatus Connected { get; } = new("connected"); - - /// The Connector service reports an unusable connection. - public static ConnectorCatalogStatus Error { get; } = new("error"); - - /// The service returned a future or unrecognized state. - public static ConnectorCatalogStatus Unknown { get; } = new("unknown"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ConnectorCatalogStatus left, ConnectorCatalogStatus right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ConnectorCatalogStatus left, ConnectorCatalogStatus right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ConnectorAuthorizationScope left, ConnectorAuthorizationScope right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ConnectorCatalogStatus other && Equals(other); + public override bool Equals(object? obj) => obj is ConnectorAuthorizationScope other && Equals(other); /// - public bool Equals(ConnectorCatalogStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ConnectorAuthorizationScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -37864,20 +42474,20 @@ public ConnectorCatalogStatus(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 ConnectorCatalogStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ConnectorAuthorizationScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ConnectorCatalogStatus value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ConnectorAuthorizationScope value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ConnectorCatalogStatus)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ConnectorAuthorizationScope)); } } } @@ -37961,6 +42571,81 @@ public override void Write(Utf8JsonWriter writer, ConnectorMcpStatus value, Json } +/// What retrying did for one plugin required by managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedPluginRetryStatus : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedPluginRetryStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The plugin was missing and is now installed. + public static ManagedPluginRetryStatus Installed { get; } = new("installed"); + + /// An update was available and is now installed. + public static ManagedPluginRetryStatus Updated { get; } = new("updated"); + + /// The plugin was already installed and current, so nothing was done. + public static ManagedPluginRetryStatus AlreadyPresent { get; } = new("already_present"); + + /// Checking, installing, or updating the plugin failed. See `error`. + public static ManagedPluginRetryStatus Failed { get; } = new("failed"); + + /// The plugin was not prepared because another session was changing plugins or the managed settings changed during the retry. It is prepared again before a later message. + public static ManagedPluginRetryStatus Deferred { get; } = new("deferred"); + + /// The session's managed settings do not require this plugin, so nothing was done. + public static ManagedPluginRetryStatus NotRequired { get; } = new("not_required"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedPluginRetryStatus left, ManagedPluginRetryStatus right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedPluginRetryStatus left, ManagedPluginRetryStatus right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedPluginRetryStatus other && Equals(other); + + /// + public bool Equals(ManagedPluginRetryStatus 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 ManagedPluginRetryStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedPluginRetryStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedPluginRetryStatus)); + } + } +} + + /// Allowed values for the `OptionsUpdateAdditionalContentExclusionPolicyScope` enumeration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -38410,17 +43095,467 @@ public ShellInitProfile(string value) /// Allow automatic non-interactive profile loading when supported. Explicit initScripts still run. public static ShellInitProfile NonInteractive { get; } = new("non-interactive"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ShellInitProfile left, ShellInitProfile right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ShellInitProfile left, ShellInitProfile right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ShellInitProfile left, ShellInitProfile right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ShellInitProfile other && Equals(other); + + /// + public bool Equals(ShellInitProfile 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 ShellInitProfile Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ShellInitProfile value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShellInitProfile)); + } + } +} + + +/// Supported built-in shells for initialization scripts. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ShellInitScriptShell : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ShellInitScriptShell(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Source the script in the built-in Bash shell on macOS and Linux. + public static ShellInitScriptShell Bash { get; } = new("bash"); + + /// Source the script in the built-in PowerShell shell on Windows. + public static ShellInitScriptShell Powershell { get; } = new("powershell"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ShellInitScriptShell left, ShellInitScriptShell right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ShellInitScriptShell left, ShellInitScriptShell right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ShellInitScriptShell other && Equals(other); + + /// + public bool Equals(ShellInitScriptShell 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 ShellInitScriptShell Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ShellInitScriptShell value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShellInitScriptShell)); + } + } +} + + +/// Discovery source: project (.github/extensions/), user (~/.copilot/extensions/), plugin (installed plugin), or session (session-state/<id>/extensions/). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ExtensionSource : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ExtensionSource(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Extension discovered from the current project's .github/extensions directory. + public static ExtensionSource Project { get; } = new("project"); + + /// Extension discovered from the user's ~/.copilot/extensions directory. + public static ExtensionSource User { get; } = new("user"); + + /// Extension contributed by an installed plugin. + public static ExtensionSource Plugin { get; } = new("plugin"); + + /// Extension discovered from the current session's state directory (loaded only for this session). + public static ExtensionSource Session { get; } = new("session"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ExtensionSource left, ExtensionSource right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ExtensionSource left, ExtensionSource right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ExtensionSource other && Equals(other); + + /// + public bool Equals(ExtensionSource 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 ExtensionSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ExtensionSource value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExtensionSource)); + } + } +} + + +/// Current status: running, disabled, failed, or starting. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ExtensionStatus : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ExtensionStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The extension process is running. + public static ExtensionStatus Running { get; } = new("running"); + + /// The extension is installed but disabled. + public static ExtensionStatus Disabled { get; } = new("disabled"); + + /// The extension failed to start or crashed. + public static ExtensionStatus Failed { get; } = new("failed"); + + /// The extension process is starting. + public static ExtensionStatus Starting { get; } = new("starting"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ExtensionStatus left, ExtensionStatus right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ExtensionStatus left, ExtensionStatus right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ExtensionStatus other && Equals(other); + + /// + public bool Equals(ExtensionStatus 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 ExtensionStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ExtensionStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExtensionStatus)); + } + } +} + + +/// Type of GitHub reference. +[Experimental(global::GitHub.Copilot.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)); + } + } +} + + +/// Custom input-format kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct BuiltinToolFormatType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public BuiltinToolFormatType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The tool input is parsed with the supplied grammar. + public static BuiltinToolFormatType Grammar { get; } = new("grammar"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(BuiltinToolFormatType left, BuiltinToolFormatType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(BuiltinToolFormatType left, BuiltinToolFormatType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is BuiltinToolFormatType other && Equals(other); + + /// + public bool Equals(BuiltinToolFormatType 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 BuiltinToolFormatType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, BuiltinToolFormatType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(BuiltinToolFormatType)); + } + } +} + + +/// Root JSON Schema type for a built-in tool input. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct BuiltinToolInputSchemaType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public BuiltinToolInputSchemaType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The tool accepts a JSON object. + public static BuiltinToolInputSchemaType Object { get; } = new("object"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(BuiltinToolInputSchemaType left, BuiltinToolInputSchemaType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(BuiltinToolInputSchemaType left, BuiltinToolInputSchemaType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is BuiltinToolInputSchemaType other && Equals(other); + + /// + public bool Equals(BuiltinToolInputSchemaType 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 BuiltinToolInputSchemaType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, BuiltinToolInputSchemaType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(BuiltinToolInputSchemaType)); + } + } +} + + +/// Binary result type discriminator. Use "image" for images and "resource" for other binary data. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ExternalToolTextResultForLlmBinaryResultsForLlmType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ExternalToolTextResultForLlmBinaryResultsForLlmType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Binary image data. + public static ExternalToolTextResultForLlmBinaryResultsForLlmType Image { get; } = new("image"); + + /// Other binary resource data. + public static ExternalToolTextResultForLlmBinaryResultsForLlmType Resource { get; } = new("resource"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ExternalToolTextResultForLlmBinaryResultsForLlmType left, ExternalToolTextResultForLlmBinaryResultsForLlmType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ShellInitProfile left, ShellInitProfile right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ExternalToolTextResultForLlmBinaryResultsForLlmType left, ExternalToolTextResultForLlmBinaryResultsForLlmType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ShellInitProfile other && Equals(other); + public override bool Equals(object? obj) => obj is ExternalToolTextResultForLlmBinaryResultsForLlmType other && Equals(other); /// - public bool Equals(ShellInitProfile other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ExternalToolTextResultForLlmBinaryResultsForLlmType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38428,62 +43563,62 @@ public ShellInitProfile(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 ShellInitProfile Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ExternalToolTextResultForLlmBinaryResultsForLlmType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ShellInitProfile value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ExternalToolTextResultForLlmBinaryResultsForLlmType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShellInitProfile)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExternalToolTextResultForLlmBinaryResultsForLlmType)); } } } -/// Supported built-in shells for initialization scripts. +/// Theme variant this icon is intended for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ShellInitScriptShell : IEquatable +public readonly struct ExternalToolTextResultForLlmContentResourceLinkIconTheme : 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 ShellInitScriptShell(string value) + public ExternalToolTextResultForLlmContentResourceLinkIconTheme(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; - /// Source the script in the built-in Bash shell on macOS and Linux. - public static ShellInitScriptShell Bash { get; } = new("bash"); + /// Icon intended for light themes. + public static ExternalToolTextResultForLlmContentResourceLinkIconTheme Light { get; } = new("light"); - /// Source the script in the built-in PowerShell shell on Windows. - public static ShellInitScriptShell Powershell { get; } = new("powershell"); + /// Icon intended for dark themes. + public static ExternalToolTextResultForLlmContentResourceLinkIconTheme Dark { get; } = new("dark"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ShellInitScriptShell left, ShellInitScriptShell right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ExternalToolTextResultForLlmContentResourceLinkIconTheme left, ExternalToolTextResultForLlmContentResourceLinkIconTheme right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ShellInitScriptShell left, ShellInitScriptShell right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ExternalToolTextResultForLlmContentResourceLinkIconTheme left, ExternalToolTextResultForLlmContentResourceLinkIconTheme right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ShellInitScriptShell other && Equals(other); + public override bool Equals(object? obj) => obj is ExternalToolTextResultForLlmContentResourceLinkIconTheme other && Equals(other); /// - public bool Equals(ShellInitScriptShell other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ExternalToolTextResultForLlmContentResourceLinkIconTheme other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38491,62 +43626,71 @@ public ShellInitScriptShell(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 ShellInitScriptShell Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ExternalToolTextResultForLlmContentResourceLinkIconTheme Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ShellInitScriptShell value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ExternalToolTextResultForLlmContentResourceLinkIconTheme value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShellInitScriptShell)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExternalToolTextResultForLlmContentResourceLinkIconTheme)); } } } -/// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. +/// Execution outcome classification. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct OptionsUpdateToolFilterPrecedence : IEquatable +public readonly struct ToolResultType : 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 OptionsUpdateToolFilterPrecedence(string value) + public ToolResultType(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; - /// If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. - public static OptionsUpdateToolFilterPrecedence Available { get; } = new("available"); + /// The tool completed successfully. + public static ToolResultType Success { get; } = new("success"); - /// A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. - public static OptionsUpdateToolFilterPrecedence Excluded { get; } = new("excluded"); + /// The tool failed. + public static ToolResultType Failure { get; } = new("failure"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => left.Equals(right); + /// The tool exceeded its execution timeout. + public static ToolResultType Timeout { get; } = new("timeout"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => !(left == right); + /// The tool request was rejected before execution. + public static ToolResultType Rejected { get; } = new("rejected"); + + /// Permission policy denied the tool request. + public static ToolResultType Denied { get; } = new("denied"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ToolResultType left, ToolResultType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ToolResultType left, ToolResultType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is OptionsUpdateToolFilterPrecedence other && Equals(other); + public override bool Equals(object? obj) => obj is ToolResultType other && Equals(other); /// - public bool Equals(OptionsUpdateToolFilterPrecedence other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ToolResultType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38554,68 +43698,62 @@ public OptionsUpdateToolFilterPrecedence(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 OptionsUpdateToolFilterPrecedence Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ToolResultType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, OptionsUpdateToolFilterPrecedence value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ToolResultType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(OptionsUpdateToolFilterPrecedence)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ToolResultType)); } } } -/// Discovery source: project (.github/extensions/), user (~/.copilot/extensions/), plugin (installed plugin), or session (session-state/<id>/extensions/). +/// Controls whether the runtime may defer loading an external tool definition. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ExtensionSource : IEquatable +public readonly struct ProtocolExternalToolDefer : 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 ExtensionSource(string value) + public ProtocolExternalToolDefer(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; - /// Extension discovered from the current project's .github/extensions directory. - public static ExtensionSource Project { get; } = new("project"); - - /// Extension discovered from the user's ~/.copilot/extensions directory. - public static ExtensionSource User { get; } = new("user"); - - /// Extension contributed by an installed plugin. - public static ExtensionSource Plugin { get; } = new("plugin"); + /// The runtime may defer the tool according to its tool-loading policy. + public static ProtocolExternalToolDefer Auto { get; } = new("auto"); - /// Extension discovered from the current session's state directory (loaded only for this session). - public static ExtensionSource Session { get; } = new("session"); + /// The runtime must include the tool without deferring it. + public static ProtocolExternalToolDefer Never { get; } = new("never"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ExtensionSource left, ExtensionSource right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProtocolExternalToolDefer left, ProtocolExternalToolDefer right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ExtensionSource left, ExtensionSource right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProtocolExternalToolDefer left, ProtocolExternalToolDefer right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ExtensionSource other && Equals(other); + public override bool Equals(object? obj) => obj is ProtocolExternalToolDefer other && Equals(other); /// - public bool Equals(ExtensionSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProtocolExternalToolDefer other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38623,68 +43761,65 @@ public ExtensionSource(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 ExtensionSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProtocolExternalToolDefer Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ExtensionSource value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProtocolExternalToolDefer value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExtensionSource)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProtocolExternalToolDefer)); } } } -/// Current status: running, disabled, failed, or starting. +/// Context tier override for matching subagents. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ExtensionStatus : IEquatable +public readonly struct SubagentSettingsEntryContextTier : 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 ExtensionStatus(string value) + public SubagentSettingsEntryContextTier(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; - /// The extension process is running. - public static ExtensionStatus Running { get; } = new("running"); - - /// The extension is installed but disabled. - public static ExtensionStatus Disabled { get; } = new("disabled"); + /// Inherit the parent session's effective context tier at dispatch time. + public static SubagentSettingsEntryContextTier Inherit { get; } = new("inherit"); - /// The extension failed to start or crashed. - public static ExtensionStatus Failed { get; } = new("failed"); + /// Use the model's default context window. + public static SubagentSettingsEntryContextTier Default { get; } = new("default"); - /// The extension process is starting. - public static ExtensionStatus Starting { get; } = new("starting"); + /// Pin the subagent to the long-context tier when supported. + public static SubagentSettingsEntryContextTier LongContext { get; } = new("long_context"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ExtensionStatus left, ExtensionStatus right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SubagentSettingsEntryContextTier left, SubagentSettingsEntryContextTier right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ExtensionStatus left, ExtensionStatus right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SubagentSettingsEntryContextTier left, SubagentSettingsEntryContextTier right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ExtensionStatus other && Equals(other); + public override bool Equals(object? obj) => obj is SubagentSettingsEntryContextTier other && Equals(other); /// - public bool Equals(ExtensionStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SubagentSettingsEntryContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38692,65 +43827,62 @@ public ExtensionStatus(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 ExtensionStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SubagentSettingsEntryContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ExtensionStatus value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SubagentSettingsEntryContextTier value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExtensionStatus)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SubagentSettingsEntryContextTier)); } } } -/// Type of GitHub reference. +/// A session-scoped sandbox transition applied while handling a slash command. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PushAttachmentGitHubReferenceType : IEquatable +public readonly struct SandboxSessionChange : 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 PushAttachmentGitHubReferenceType(string value) + public SandboxSessionChange(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 PushAttachmentGitHubReferenceType Issue { get; } = new("issue"); - - /// GitHub pull request reference. - public static PushAttachmentGitHubReferenceType Pr { get; } = new("pr"); + /// The sandbox is off for the rest of this session; nothing was persisted and a new session starts from managed policy. + public static SandboxSessionChange Disabled { get; } = new("disabled"); - /// GitHub discussion reference. - public static PushAttachmentGitHubReferenceType Discussion { get; } = new("discussion"); + /// A previous session-scoped opt-out was cleared and the sandbox is enforced again. + public static SandboxSessionChange Restored { get; } = new("restored"); - /// 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 equivalent. + public static bool operator ==(SandboxSessionChange left, SandboxSessionChange right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PushAttachmentGitHubReferenceType left, PushAttachmentGitHubReferenceType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SandboxSessionChange left, SandboxSessionChange right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PushAttachmentGitHubReferenceType other && Equals(other); + public override bool Equals(object? obj) => obj is SandboxSessionChange other && Equals(other); /// - public bool Equals(PushAttachmentGitHubReferenceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SandboxSessionChange other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38758,59 +43890,59 @@ public PushAttachmentGitHubReferenceType(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 PushAttachmentGitHubReferenceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SandboxSessionChange 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) + public override void Write(Utf8JsonWriter writer, SandboxSessionChange value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PushAttachmentGitHubReferenceType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SandboxSessionChange)); } } } -/// Custom input-format kind. +/// Defines the allowed values. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct BuiltinToolFormatType : IEquatable +public readonly struct CommandsInvocationOrigin : 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 BuiltinToolFormatType(string value) + public CommandsInvocationOrigin(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; - /// The tool input is parsed with the supplied grammar. - public static BuiltinToolFormatType Grammar { get; } = new("grammar"); + /// Gets the settings value. + public static CommandsInvocationOrigin Settings { get; } = new("settings"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(BuiltinToolFormatType left, BuiltinToolFormatType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(CommandsInvocationOrigin left, CommandsInvocationOrigin right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(BuiltinToolFormatType left, BuiltinToolFormatType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(CommandsInvocationOrigin left, CommandsInvocationOrigin right) => !(left == right); /// - public override bool Equals(object? obj) => obj is BuiltinToolFormatType other && Equals(other); + public override bool Equals(object? obj) => obj is CommandsInvocationOrigin other && Equals(other); /// - public bool Equals(BuiltinToolFormatType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(CommandsInvocationOrigin other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38818,59 +43950,62 @@ public BuiltinToolFormatType(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 BuiltinToolFormatType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override CommandsInvocationOrigin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, BuiltinToolFormatType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, CommandsInvocationOrigin value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(BuiltinToolFormatType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(CommandsInvocationOrigin)); } } } -/// Root JSON Schema type for a built-in tool input. +/// Whether a pending slash-command invocation effect was applied or cancelled by the host. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct BuiltinToolInputSchemaType : IEquatable +public readonly struct CommandsInvocationEffectOutcome : 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 BuiltinToolInputSchemaType(string value) + public CommandsInvocationEffectOutcome(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; - /// The tool accepts a JSON object. - public static BuiltinToolInputSchemaType Object { get; } = new("object"); + /// The host applied the pending invocation effect. + public static CommandsInvocationEffectOutcome Applied { get; } = new("applied"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(BuiltinToolInputSchemaType left, BuiltinToolInputSchemaType right) => left.Equals(right); + /// The host cancelled the pending invocation effect, so any provisional state must be reverted. + public static CommandsInvocationEffectOutcome Cancelled { get; } = new("cancelled"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(BuiltinToolInputSchemaType left, BuiltinToolInputSchemaType right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(CommandsInvocationEffectOutcome left, CommandsInvocationEffectOutcome right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(CommandsInvocationEffectOutcome left, CommandsInvocationEffectOutcome right) => !(left == right); /// - public override bool Equals(object? obj) => obj is BuiltinToolInputSchemaType other && Equals(other); + public override bool Equals(object? obj) => obj is CommandsInvocationEffectOutcome other && Equals(other); /// - public bool Equals(BuiltinToolInputSchemaType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(CommandsInvocationEffectOutcome other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38878,62 +44013,65 @@ public BuiltinToolInputSchemaType(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 BuiltinToolInputSchemaType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override CommandsInvocationEffectOutcome Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, BuiltinToolInputSchemaType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, CommandsInvocationEffectOutcome value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(BuiltinToolInputSchemaType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(CommandsInvocationEffectOutcome)); } } } -/// Binary result type discriminator. Use "image" for images and "resource" for other binary data. +/// The user's response: accept (submitted), decline (rejected), or cancel (dismissed). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ExternalToolTextResultForLlmBinaryResultsForLlmType : IEquatable +public readonly struct UIElicitationResponseAction : 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 ExternalToolTextResultForLlmBinaryResultsForLlmType(string value) + public UIElicitationResponseAction(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; - /// Binary image data. - public static ExternalToolTextResultForLlmBinaryResultsForLlmType Image { get; } = new("image"); + /// The user submitted the requested form values. + public static UIElicitationResponseAction Accept { get; } = new("accept"); - /// Other binary resource data. - public static ExternalToolTextResultForLlmBinaryResultsForLlmType Resource { get; } = new("resource"); + /// The user explicitly declined to provide the requested input. + public static UIElicitationResponseAction Decline { get; } = new("decline"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ExternalToolTextResultForLlmBinaryResultsForLlmType left, ExternalToolTextResultForLlmBinaryResultsForLlmType right) => left.Equals(right); + /// The user dismissed the elicitation request. + public static UIElicitationResponseAction Cancel { get; } = new("cancel"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ExternalToolTextResultForLlmBinaryResultsForLlmType left, ExternalToolTextResultForLlmBinaryResultsForLlmType right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(UIElicitationResponseAction left, UIElicitationResponseAction right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(UIElicitationResponseAction left, UIElicitationResponseAction right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ExternalToolTextResultForLlmBinaryResultsForLlmType other && Equals(other); + public override bool Equals(object? obj) => obj is UIElicitationResponseAction other && Equals(other); /// - public bool Equals(ExternalToolTextResultForLlmBinaryResultsForLlmType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(UIElicitationResponseAction other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -38941,62 +44079,59 @@ public ExternalToolTextResultForLlmBinaryResultsForLlmType(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 ExternalToolTextResultForLlmBinaryResultsForLlmType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override UIElicitationResponseAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ExternalToolTextResultForLlmBinaryResultsForLlmType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, UIElicitationResponseAction value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExternalToolTextResultForLlmBinaryResultsForLlmType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UIElicitationResponseAction)); } } } -/// Theme variant this icon is intended for. +/// Structured MCP elicitation mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ExternalToolTextResultForLlmContentResourceLinkIconTheme : IEquatable +public readonly struct McpElicitationFormMode : 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 ExternalToolTextResultForLlmContentResourceLinkIconTheme(string value) + public McpElicitationFormMode(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; - /// Icon intended for light themes. - public static ExternalToolTextResultForLlmContentResourceLinkIconTheme Light { get; } = new("light"); - - /// Icon intended for dark themes. - public static ExternalToolTextResultForLlmContentResourceLinkIconTheme Dark { get; } = new("dark"); + /// Gets the form value. + public static McpElicitationFormMode Form { get; } = new("form"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ExternalToolTextResultForLlmContentResourceLinkIconTheme left, ExternalToolTextResultForLlmContentResourceLinkIconTheme right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(McpElicitationFormMode left, McpElicitationFormMode right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ExternalToolTextResultForLlmContentResourceLinkIconTheme left, ExternalToolTextResultForLlmContentResourceLinkIconTheme right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(McpElicitationFormMode left, McpElicitationFormMode right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ExternalToolTextResultForLlmContentResourceLinkIconTheme other && Equals(other); + public override bool Equals(object? obj) => obj is McpElicitationFormMode other && Equals(other); /// - public bool Equals(ExternalToolTextResultForLlmContentResourceLinkIconTheme other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(McpElicitationFormMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39004,71 +44139,65 @@ public ExternalToolTextResultForLlmContentResourceLinkIconTheme(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 ExternalToolTextResultForLlmContentResourceLinkIconTheme Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override McpElicitationFormMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ExternalToolTextResultForLlmContentResourceLinkIconTheme value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, McpElicitationFormMode value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ExternalToolTextResultForLlmContentResourceLinkIconTheme)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(McpElicitationFormMode)); } } } -/// Execution outcome classification. +/// User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ToolResultType : IEquatable +public readonly struct UIAutoModeSwitchResponse : 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 ToolResultType(string value) + public UIAutoModeSwitchResponse(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; - /// The tool completed successfully. - public static ToolResultType Success { get; } = new("success"); - - /// The tool failed. - public static ToolResultType Failure { get; } = new("failure"); - - /// The tool exceeded its execution timeout. - public static ToolResultType Timeout { get; } = new("timeout"); + /// Allow the automatic mode switch for this turn. + public static UIAutoModeSwitchResponse Yes { get; } = new("yes"); - /// The tool request was rejected before execution. - public static ToolResultType Rejected { get; } = new("rejected"); + /// Allow this mode switch and persist the preference. + public static UIAutoModeSwitchResponse YesAlways { get; } = new("yes_always"); - /// Permission policy denied the tool request. - public static ToolResultType Denied { get; } = new("denied"); + /// Decline the automatic mode switch. + public static UIAutoModeSwitchResponse No { get; } = new("no"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ToolResultType left, ToolResultType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(UIAutoModeSwitchResponse left, UIAutoModeSwitchResponse right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ToolResultType left, ToolResultType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(UIAutoModeSwitchResponse left, UIAutoModeSwitchResponse right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ToolResultType other && Equals(other); + public override bool Equals(object? obj) => obj is UIAutoModeSwitchResponse other && Equals(other); /// - public bool Equals(ToolResultType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(UIAutoModeSwitchResponse other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39076,62 +44205,68 @@ public ToolResultType(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 ToolResultType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override UIAutoModeSwitchResponse Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ToolResultType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, UIAutoModeSwitchResponse value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ToolResultType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UIAutoModeSwitchResponse)); } } } -/// Controls whether the runtime may defer loading an external tool definition. +/// User action selected for an exhausted session limit. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ProtocolExternalToolDefer : IEquatable +public readonly struct UISessionLimitsExhaustedResponseAction : 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 ProtocolExternalToolDefer(string value) + public UISessionLimitsExhaustedResponseAction(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; - /// The runtime may defer the tool according to its tool-loading policy. - public static ProtocolExternalToolDefer Auto { get; } = new("auto"); + /// Increase the current max by an exact AI Credits amount. + public static UISessionLimitsExhaustedResponseAction Add { get; } = new("add"); - /// The runtime must include the tool without deferring it. - public static ProtocolExternalToolDefer Never { get; } = new("never"); + /// Set a new absolute max AI Credits value. + public static UISessionLimitsExhaustedResponseAction Set { get; } = new("set"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ProtocolExternalToolDefer left, ProtocolExternalToolDefer right) => left.Equals(right); + /// Remove the current session limit. + public static UISessionLimitsExhaustedResponseAction Unset { get; } = new("unset"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ProtocolExternalToolDefer left, ProtocolExternalToolDefer right) => !(left == right); + /// Leave the limit unchanged and cancel the blocked model request. + public static UISessionLimitsExhaustedResponseAction Cancel { get; } = new("cancel"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(UISessionLimitsExhaustedResponseAction left, UISessionLimitsExhaustedResponseAction right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(UISessionLimitsExhaustedResponseAction left, UISessionLimitsExhaustedResponseAction right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ProtocolExternalToolDefer other && Equals(other); + public override bool Equals(object? obj) => obj is UISessionLimitsExhaustedResponseAction other && Equals(other); /// - public bool Equals(ProtocolExternalToolDefer other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(UISessionLimitsExhaustedResponseAction other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39139,65 +44274,68 @@ public ProtocolExternalToolDefer(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 ProtocolExternalToolDefer Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override UISessionLimitsExhaustedResponseAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ProtocolExternalToolDefer value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, UISessionLimitsExhaustedResponseAction value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProtocolExternalToolDefer)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UISessionLimitsExhaustedResponseAction)); } } } -/// Context tier override for matching subagents. +/// The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SubagentSettingsEntryContextTier : IEquatable +public readonly struct UIExitPlanModeAction : 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 SubagentSettingsEntryContextTier(string value) + public UIExitPlanModeAction(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; - /// Inherit the parent session's effective context tier at dispatch time. - public static SubagentSettingsEntryContextTier Inherit { get; } = new("inherit"); + /// Exit plan mode without starting implementation. + public static UIExitPlanModeAction ExitOnly { get; } = new("exit_only"); - /// Use the model's default context window. - public static SubagentSettingsEntryContextTier Default { get; } = new("default"); + /// Exit plan mode and continue interactively. + public static UIExitPlanModeAction Interactive { get; } = new("interactive"); - /// Pin the subagent to the long-context tier when supported. - public static SubagentSettingsEntryContextTier LongContext { get; } = new("long_context"); + /// Exit plan mode and continue in autopilot mode. + public static UIExitPlanModeAction Autopilot { get; } = new("autopilot"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SubagentSettingsEntryContextTier left, SubagentSettingsEntryContextTier right) => left.Equals(right); + /// Exit plan mode and continue in autopilot mode with parallel subagent execution. + public static UIExitPlanModeAction AutopilotFleet { get; } = new("autopilot_fleet"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SubagentSettingsEntryContextTier left, SubagentSettingsEntryContextTier right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(UIExitPlanModeAction left, UIExitPlanModeAction right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(UIExitPlanModeAction left, UIExitPlanModeAction right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SubagentSettingsEntryContextTier other && Equals(other); + public override bool Equals(object? obj) => obj is UIExitPlanModeAction other && Equals(other); /// - public bool Equals(SubagentSettingsEntryContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(UIExitPlanModeAction other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39205,62 +44343,62 @@ public SubagentSettingsEntryContextTier(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 SubagentSettingsEntryContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override UIExitPlanModeAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SubagentSettingsEntryContextTier value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, UIExitPlanModeAction value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SubagentSettingsEntryContextTier)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UIExitPlanModeAction)); } } } -/// A session-scoped sandbox transition applied while handling a slash command. +/// Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SandboxSessionChange : IEquatable +public readonly struct PermissionsConfigureAdditionalContentExclusionPolicyScope : 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 SandboxSessionChange(string value) + public PermissionsConfigureAdditionalContentExclusionPolicyScope(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; - /// The sandbox is off for the rest of this session; nothing was persisted and a new session starts from managed policy. - public static SandboxSessionChange Disabled { get; } = new("disabled"); + /// The content exclusion policy applies to the current repository. + public static PermissionsConfigureAdditionalContentExclusionPolicyScope Repo { get; } = new("repo"); - /// A previous session-scoped opt-out was cleared and the sandbox is enforced again. - public static SandboxSessionChange Restored { get; } = new("restored"); + /// The content exclusion policy applies across all repositories. + public static PermissionsConfigureAdditionalContentExclusionPolicyScope All { get; } = new("all"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SandboxSessionChange left, SandboxSessionChange right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(PermissionsConfigureAdditionalContentExclusionPolicyScope left, PermissionsConfigureAdditionalContentExclusionPolicyScope right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SandboxSessionChange left, SandboxSessionChange right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(PermissionsConfigureAdditionalContentExclusionPolicyScope left, PermissionsConfigureAdditionalContentExclusionPolicyScope right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SandboxSessionChange other && Equals(other); + public override bool Equals(object? obj) => obj is PermissionsConfigureAdditionalContentExclusionPolicyScope other && Equals(other); /// - public bool Equals(SandboxSessionChange other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(PermissionsConfigureAdditionalContentExclusionPolicyScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39268,59 +44406,71 @@ public SandboxSessionChange(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 SandboxSessionChange Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PermissionsConfigureAdditionalContentExclusionPolicyScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SandboxSessionChange value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PermissionsConfigureAdditionalContentExclusionPolicyScope value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SandboxSessionChange)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsConfigureAdditionalContentExclusionPolicyScope)); } } } -/// Defines the allowed values. +/// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct CommandsInvocationOrigin : IEquatable +public readonly struct PermissionsSetApproveAllSource : 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 CommandsInvocationOrigin(string value) + public PermissionsSetApproveAllSource(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; - /// Gets the settings value. - public static CommandsInvocationOrigin Settings { get; } = new("settings"); + /// Allow-all was enabled from a CLI command-line flag. + public static PermissionsSetApproveAllSource CliFlag { get; } = new("cli_flag"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(CommandsInvocationOrigin left, CommandsInvocationOrigin right) => left.Equals(right); + /// Allow-all was enabled by a slash command. + public static PermissionsSetApproveAllSource SlashCommand { get; } = new("slash_command"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(CommandsInvocationOrigin left, CommandsInvocationOrigin right) => !(left == right); + /// Allow-all was enabled by confirming autopilot behavior. + public static PermissionsSetApproveAllSource AutopilotConfirmation { get; } = new("autopilot_confirmation"); + + /// Allow-all was enabled at startup by the `defaultPermissionMode` user setting. + public static PermissionsSetApproveAllSource UserSetting { get; } = new("user_setting"); + + /// Allow-all was enabled through an RPC caller. + public static PermissionsSetApproveAllSource Rpc { get; } = new("rpc"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(PermissionsSetApproveAllSource left, PermissionsSetApproveAllSource right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(PermissionsSetApproveAllSource left, PermissionsSetApproveAllSource right) => !(left == right); /// - public override bool Equals(object? obj) => obj is CommandsInvocationOrigin other && Equals(other); + public override bool Equals(object? obj) => obj is PermissionsSetApproveAllSource other && Equals(other); /// - public bool Equals(CommandsInvocationOrigin other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(PermissionsSetApproveAllSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39328,62 +44478,74 @@ public CommandsInvocationOrigin(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 CommandsInvocationOrigin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PermissionsSetApproveAllSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, CommandsInvocationOrigin value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PermissionsSetApproveAllSource value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(CommandsInvocationOrigin)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsSetApproveAllSource)); } } } -/// Whether a pending slash-command invocation effect was applied or cancelled by the host. +/// Optional source for permission-mode telemetry. `organization_targeting` is reserved for startup selection after the authenticated account matches an organization targeting policy; SDK callers default to `rpc` and cannot claim targeting provenance. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct CommandsInvocationEffectOutcome : IEquatable +public readonly struct PermissionModeSource : 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 CommandsInvocationEffectOutcome(string value) + public PermissionModeSource(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; - /// The host applied the pending invocation effect. - public static CommandsInvocationEffectOutcome Applied { get; } = new("applied"); + /// The mode was set from a CLI command-line flag. + public static PermissionModeSource CliFlag { get; } = new("cli_flag"); - /// The host cancelled the pending invocation effect, so any provisional state must be reverted. - public static CommandsInvocationEffectOutcome Cancelled { get; } = new("cancelled"); + /// The mode was set by a slash command. + public static PermissionModeSource SlashCommand { get; } = new("slash_command"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(CommandsInvocationEffectOutcome left, CommandsInvocationEffectOutcome right) => left.Equals(right); + /// The mode was set by confirming autopilot behavior. + public static PermissionModeSource AutopilotConfirmation { get; } = new("autopilot_confirmation"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(CommandsInvocationEffectOutcome left, CommandsInvocationEffectOutcome right) => !(left == right); + /// The mode was set at startup by the `defaultPermissionMode` user setting. + public static PermissionModeSource UserSetting { get; } = new("user_setting"); + + /// The mode was set at startup because the authenticated account matched an organization targeting policy. + public static PermissionModeSource OrganizationTargeting { get; } = new("organization_targeting"); + + /// The mode was set through an RPC caller. + public static PermissionModeSource Rpc { get; } = new("rpc"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(PermissionModeSource left, PermissionModeSource right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(PermissionModeSource left, PermissionModeSource right) => !(left == right); /// - public override bool Equals(object? obj) => obj is CommandsInvocationEffectOutcome other && Equals(other); + public override bool Equals(object? obj) => obj is PermissionModeSource other && Equals(other); /// - public bool Equals(CommandsInvocationEffectOutcome other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(PermissionModeSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39391,65 +44553,62 @@ public CommandsInvocationEffectOutcome(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 CommandsInvocationEffectOutcome Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PermissionModeSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, CommandsInvocationEffectOutcome value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PermissionModeSource value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(CommandsInvocationEffectOutcome)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionModeSource)); } } } -/// The user's response: accept (submitted), decline (rejected), or cancel (dismissed). +/// 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(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct UIElicitationResponseAction : IEquatable +public readonly struct PermissionsModifyRulesScope : 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 UIElicitationResponseAction(string value) + public PermissionsModifyRulesScope(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; - /// The user submitted the requested form values. - public static UIElicitationResponseAction Accept { get; } = new("accept"); - - /// The user explicitly declined to provide the requested input. - public static UIElicitationResponseAction Decline { get; } = new("decline"); + /// Apply the rule change only to this session. + public static PermissionsModifyRulesScope Session { get; } = new("session"); - /// The user dismissed the elicitation request. - public static UIElicitationResponseAction Cancel { get; } = new("cancel"); + /// Persist the rule change for this project location. + public static PermissionsModifyRulesScope Location { get; } = new("location"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(UIElicitationResponseAction left, UIElicitationResponseAction right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(PermissionsModifyRulesScope left, PermissionsModifyRulesScope right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(UIElicitationResponseAction left, UIElicitationResponseAction right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(PermissionsModifyRulesScope left, PermissionsModifyRulesScope right) => !(left == right); /// - public override bool Equals(object? obj) => obj is UIElicitationResponseAction other && Equals(other); + public override bool Equals(object? obj) => obj is PermissionsModifyRulesScope other && Equals(other); /// - public bool Equals(UIElicitationResponseAction other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(PermissionsModifyRulesScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39457,59 +44616,62 @@ public UIElicitationResponseAction(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 UIElicitationResponseAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PermissionsModifyRulesScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, UIElicitationResponseAction value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PermissionsModifyRulesScope value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UIElicitationResponseAction)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsModifyRulesScope)); } } } -/// Structured MCP elicitation mode. +/// Whether the location is a git repo or directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct McpElicitationFormMode : IEquatable +public readonly struct PermissionLocationType : 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 McpElicitationFormMode(string value) + public PermissionLocationType(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; - /// Gets the form value. - public static McpElicitationFormMode Form { get; } = new("form"); + /// The permission location is persisted at the git repository root. + public static PermissionLocationType Repo { get; } = new("repo"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(McpElicitationFormMode left, McpElicitationFormMode right) => left.Equals(right); + /// The permission location is persisted at the working directory. + public static PermissionLocationType Dir { get; } = new("dir"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(McpElicitationFormMode left, McpElicitationFormMode right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(PermissionLocationType left, PermissionLocationType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(PermissionLocationType left, PermissionLocationType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is McpElicitationFormMode other && Equals(other); + public override bool Equals(object? obj) => obj is PermissionLocationType other && Equals(other); /// - public bool Equals(McpElicitationFormMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(PermissionLocationType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39517,65 +44679,65 @@ public McpElicitationFormMode(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 McpElicitationFormMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PermissionLocationType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, McpElicitationFormMode value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PermissionLocationType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(McpElicitationFormMode)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionLocationType)); } } } -/// User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). +/// The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot'). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct UIAutoModeSwitchResponse : IEquatable +public readonly struct MetadataSnapshotCurrentMode : 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 UIAutoModeSwitchResponse(string value) + public MetadataSnapshotCurrentMode(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; - /// Allow the automatic mode switch for this turn. - public static UIAutoModeSwitchResponse Yes { get; } = new("yes"); + /// The agent is responding interactively to the user. + public static MetadataSnapshotCurrentMode Interactive { get; } = new("interactive"); - /// Allow this mode switch and persist the preference. - public static UIAutoModeSwitchResponse YesAlways { get; } = new("yes_always"); + /// The agent is preparing a plan before making changes. + public static MetadataSnapshotCurrentMode Plan { get; } = new("plan"); - /// Decline the automatic mode switch. - public static UIAutoModeSwitchResponse No { get; } = new("no"); + /// The agent is working autonomously toward task completion. + public static MetadataSnapshotCurrentMode Autopilot { get; } = new("autopilot"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(UIAutoModeSwitchResponse left, UIAutoModeSwitchResponse right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(MetadataSnapshotCurrentMode left, MetadataSnapshotCurrentMode right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(UIAutoModeSwitchResponse left, UIAutoModeSwitchResponse right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(MetadataSnapshotCurrentMode left, MetadataSnapshotCurrentMode right) => !(left == right); /// - public override bool Equals(object? obj) => obj is UIAutoModeSwitchResponse other && Equals(other); + public override bool Equals(object? obj) => obj is MetadataSnapshotCurrentMode other && Equals(other); /// - public bool Equals(UIAutoModeSwitchResponse other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(MetadataSnapshotCurrentMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39583,68 +44745,62 @@ public UIAutoModeSwitchResponse(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 UIAutoModeSwitchResponse Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override MetadataSnapshotCurrentMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, UIAutoModeSwitchResponse value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, MetadataSnapshotCurrentMode value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UIAutoModeSwitchResponse)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(MetadataSnapshotCurrentMode)); } } } -/// User action selected for an exhausted session limit. +/// Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct UISessionLimitsExhaustedResponseAction : IEquatable +public readonly struct MetadataSnapshotRemoteMetadataTaskType : 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 UISessionLimitsExhaustedResponseAction(string value) + public MetadataSnapshotRemoteMetadataTaskType(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; - /// Increase the current max by an exact AI Credits amount. - public static UISessionLimitsExhaustedResponseAction Add { get; } = new("add"); - - /// Set a new absolute max AI Credits value. - public static UISessionLimitsExhaustedResponseAction Set { get; } = new("set"); - - /// Remove the current session limit. - public static UISessionLimitsExhaustedResponseAction Unset { get; } = new("unset"); + /// Remote task originated from Copilot Coding Agent. + public static MetadataSnapshotRemoteMetadataTaskType Cca { get; } = new("cca"); - /// Leave the limit unchanged and cancel the blocked model request. - public static UISessionLimitsExhaustedResponseAction Cancel { get; } = new("cancel"); + /// Remote task originated from a CLI remote-session invocation. + public static MetadataSnapshotRemoteMetadataTaskType Cli { get; } = new("cli"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(UISessionLimitsExhaustedResponseAction left, UISessionLimitsExhaustedResponseAction right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(MetadataSnapshotRemoteMetadataTaskType left, MetadataSnapshotRemoteMetadataTaskType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(UISessionLimitsExhaustedResponseAction left, UISessionLimitsExhaustedResponseAction right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(MetadataSnapshotRemoteMetadataTaskType left, MetadataSnapshotRemoteMetadataTaskType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is UISessionLimitsExhaustedResponseAction other && Equals(other); + public override bool Equals(object? obj) => obj is MetadataSnapshotRemoteMetadataTaskType other && Equals(other); /// - public bool Equals(UISessionLimitsExhaustedResponseAction other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(MetadataSnapshotRemoteMetadataTaskType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39652,68 +44808,62 @@ public UISessionLimitsExhaustedResponseAction(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 UISessionLimitsExhaustedResponseAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override MetadataSnapshotRemoteMetadataTaskType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, UISessionLimitsExhaustedResponseAction value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, MetadataSnapshotRemoteMetadataTaskType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UISessionLimitsExhaustedResponseAction)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(MetadataSnapshotRemoteMetadataTaskType)); } } } -/// The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. +/// Repository host type, if known. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct UIExitPlanModeAction : IEquatable +public readonly struct WorkspaceSummaryHostType : 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 UIExitPlanModeAction(string value) + public WorkspaceSummaryHostType(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; - /// Exit plan mode without starting implementation. - public static UIExitPlanModeAction ExitOnly { get; } = new("exit_only"); - - /// Exit plan mode and continue interactively. - public static UIExitPlanModeAction Interactive { get; } = new("interactive"); - - /// Exit plan mode and continue in autopilot mode. - public static UIExitPlanModeAction Autopilot { get; } = new("autopilot"); + /// Workspace summary repository is hosted on GitHub. + public static WorkspaceSummaryHostType GitHub { get; } = new("github"); - /// Exit plan mode and continue in autopilot mode with parallel subagent execution. - public static UIExitPlanModeAction AutopilotFleet { get; } = new("autopilot_fleet"); + /// Workspace summary repository is hosted on Azure DevOps. + public static WorkspaceSummaryHostType Ado { get; } = new("ado"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(UIExitPlanModeAction left, UIExitPlanModeAction right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(WorkspaceSummaryHostType left, WorkspaceSummaryHostType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(UIExitPlanModeAction left, UIExitPlanModeAction right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(WorkspaceSummaryHostType left, WorkspaceSummaryHostType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is UIExitPlanModeAction other && Equals(other); + public override bool Equals(object? obj) => obj is WorkspaceSummaryHostType other && Equals(other); /// - public bool Equals(UIExitPlanModeAction other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(WorkspaceSummaryHostType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39721,62 +44871,113 @@ public UIExitPlanModeAction(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 UIExitPlanModeAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override WorkspaceSummaryHostType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, UIExitPlanModeAction value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, WorkspaceSummaryHostType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UIExitPlanModeAction)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(WorkspaceSummaryHostType)); } } } -/// Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. +/// Rust-owned settings predicates exposed across the SDK boundary. Raw feature-flag names are intentionally not part of the contract. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PermissionsConfigureAdditionalContentExclusionPolicyScope : IEquatable +public readonly struct SessionSettingsPredicateName : 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 PermissionsConfigureAdditionalContentExclusionPolicyScope(string value) + public SessionSettingsPredicateName(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; - /// The content exclusion policy applies to the current repository. - public static PermissionsConfigureAdditionalContentExclusionPolicyScope Repo { get; } = new("repo"); + /// Whether the security-tools feature flag enables security tool wiring. + public static SessionSettingsPredicateName SecurityToolsEnabled { get; } = new("securityToolsEnabled"); - /// The content exclusion policy applies across all repositories. - public static PermissionsConfigureAdditionalContentExclusionPolicyScope All { get; } = new("all"); + /// Whether third-party security tools should receive the security prompt. + public static SessionSettingsPredicateName ThirdPartySecurityPromptEnabled { get; } = new("thirdPartySecurityPromptEnabled"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(PermissionsConfigureAdditionalContentExclusionPolicyScope left, PermissionsConfigureAdditionalContentExclusionPolicyScope right) => left.Equals(right); + /// Whether validation may run in parallel. + public static SessionSettingsPredicateName ParallelValidationEnabled { get; } = new("parallelValidationEnabled"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PermissionsConfigureAdditionalContentExclusionPolicyScope left, PermissionsConfigureAdditionalContentExclusionPolicyScope right) => !(left == right); + /// Whether runtime timing telemetry is enabled. + public static SessionSettingsPredicateName RuntimeTimingTelemetryEnabled { get; } = new("runtimeTimingTelemetryEnabled"); + + /// Whether the co-author hook is enabled. + public static SessionSettingsPredicateName CoAuthorHookEnabled { get; } = new("coAuthorHookEnabled"); + + /// Whether Chronicle integration is enabled. + public static SessionSettingsPredicateName ChronicleEnabled { get; } = new("chronicleEnabled"); + + /// Whether content-exclusion policy may self-fetch data. + public static SessionSettingsPredicateName ContentExclusionSelfFetchEnabled { get; } = new("contentExclusionSelfFetchEnabled"); + + /// Whether Claude Opus token-limit caps should be applied. + public static SessionSettingsPredicateName CapClaudeOpusTokenLimitsEnabled { get; } = new("capClaudeOpusTokenLimitsEnabled"); + + /// Whether code-review behavior is enabled. + public static SessionSettingsPredicateName CodeReviewFeatureEnabled { get; } = new("codeReviewFeatureEnabled"); + + /// Whether CCA should use the TypeScript autofind behavior. + public static SessionSettingsPredicateName CcaUseTsAutofindEnabled { get; } = new("ccaUseTsAutofindEnabled"); + + /// Whether the dependency checker is enabled. + public static SessionSettingsPredicateName DependencyCheckerEnabled { get; } = new("dependencyCheckerEnabled"); + + /// Whether the Dependabot checker is enabled. + public static SessionSettingsPredicateName DependabotCheckerEnabled { get; } = new("dependabotCheckerEnabled"); + + /// Whether the CodeQL checker is enabled. + public static SessionSettingsPredicateName CodeqlCheckerEnabled { get; } = new("codeqlCheckerEnabled"); + + /// Whether trivial-change handling is enabled. + public static SessionSettingsPredicateName TrivialChangeEnabled { get; } = new("trivialChangeEnabled"); + + /// Whether trivial-change skip behavior is enabled. + public static SessionSettingsPredicateName TrivialChangeSkipEnabled { get; } = new("trivialChangeSkipEnabled"); + + /// Whether trivial-change handling is enabled for code review. + public static SessionSettingsPredicateName TrivialChangeEnabledForCodeReview { get; } = new("trivialChangeEnabledForCodeReview"); + + /// Whether trivial-change skip behavior is enabled for code review. + public static SessionSettingsPredicateName TrivialChangeSkipEnabledForCodeReview { get; } = new("trivialChangeSkipEnabledForCodeReview"); + + /// Whether trivial-change handling is enabled for a specific tool. + public static SessionSettingsPredicateName TrivialChangeEnabledForTool { get; } = new("trivialChangeEnabledForTool"); + + /// Whether trivial-change skip behavior is enabled for a specific tool. + public static SessionSettingsPredicateName TrivialChangeSkipEnabledForTool { get; } = new("trivialChangeSkipEnabledForTool"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionSettingsPredicateName left, SessionSettingsPredicateName right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionSettingsPredicateName left, SessionSettingsPredicateName right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PermissionsConfigureAdditionalContentExclusionPolicyScope other && Equals(other); + public override bool Equals(object? obj) => obj is SessionSettingsPredicateName other && Equals(other); /// - public bool Equals(PermissionsConfigureAdditionalContentExclusionPolicyScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionSettingsPredicateName other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39784,71 +44985,65 @@ public PermissionsConfigureAdditionalContentExclusionPolicyScope(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 PermissionsConfigureAdditionalContentExclusionPolicyScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionSettingsPredicateName Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, PermissionsConfigureAdditionalContentExclusionPolicyScope value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionSettingsPredicateName value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsConfigureAdditionalContentExclusionPolicyScope)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionSettingsPredicateName)); } } } -/// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers. +/// Signal to send (default: SIGTERM). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PermissionsSetApproveAllSource : IEquatable +public readonly struct ShellKillSignal : 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 PermissionsSetApproveAllSource(string value) + public ShellKillSignal(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; - /// Allow-all was enabled from a CLI command-line flag. - public static PermissionsSetApproveAllSource CliFlag { get; } = new("cli_flag"); - - /// Allow-all was enabled by a slash command. - public static PermissionsSetApproveAllSource SlashCommand { get; } = new("slash_command"); - - /// Allow-all was enabled by confirming autopilot behavior. - public static PermissionsSetApproveAllSource AutopilotConfirmation { get; } = new("autopilot_confirmation"); + /// Request graceful process termination. + public static ShellKillSignal SIGTERM { get; } = new("SIGTERM"); - /// Allow-all was enabled at startup by the `defaultPermissionMode` user setting. - public static PermissionsSetApproveAllSource UserSetting { get; } = new("user_setting"); + /// Forcefully terminate the process. + public static ShellKillSignal SIGKILL { get; } = new("SIGKILL"); - /// Allow-all was enabled through an RPC caller. - public static PermissionsSetApproveAllSource Rpc { get; } = new("rpc"); + /// Send an interrupt signal to the process. + public static ShellKillSignal SIGINT { get; } = new("SIGINT"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(PermissionsSetApproveAllSource left, PermissionsSetApproveAllSource right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ShellKillSignal left, ShellKillSignal right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PermissionsSetApproveAllSource left, PermissionsSetApproveAllSource right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ShellKillSignal left, ShellKillSignal right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PermissionsSetApproveAllSource other && Equals(other); + public override bool Equals(object? obj) => obj is ShellKillSignal other && Equals(other); /// - public bool Equals(PermissionsSetApproveAllSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ShellKillSignal other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39856,74 +45051,61 @@ public PermissionsSetApproveAllSource(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 PermissionsSetApproveAllSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ShellKillSignal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, PermissionsSetApproveAllSource value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ShellKillSignal value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsSetApproveAllSource)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShellKillSignal)); } } } -/// Optional source for permission-mode telemetry. `organization_targeting` is reserved for startup selection after the authenticated account matches an organization targeting policy; SDK callers default to `rpc` and cannot claim targeting provenance. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +/// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PermissionModeSource : IEquatable +public readonly struct SessionHistoryCompactRequestTrigger : 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 PermissionModeSource(string value) + public SessionHistoryCompactRequestTrigger(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; - /// The mode was set from a CLI command-line flag. - public static PermissionModeSource CliFlag { get; } = new("cli_flag"); - - /// The mode was set by a slash command. - public static PermissionModeSource SlashCommand { get; } = new("slash_command"); - - /// The mode was set by confirming autopilot behavior. - public static PermissionModeSource AutopilotConfirmation { get; } = new("autopilot_confirmation"); - - /// The mode was set at startup by the `defaultPermissionMode` user setting. - public static PermissionModeSource UserSetting { get; } = new("user_setting"); - - /// The mode was set at startup because the authenticated account matched an organization targeting policy. - public static PermissionModeSource OrganizationTargeting { get; } = new("organization_targeting"); + /// User-requested compaction, e.g. the /compact command or a direct history.compact call. + public static SessionHistoryCompactRequestTrigger Manual { get; } = new("manual"); - /// The mode was set through an RPC caller. - public static PermissionModeSource Rpc { get; } = new("rpc"); + /// Compaction requested while switching to a model with a smaller context window. + public static SessionHistoryCompactRequestTrigger ModelSwitch { get; } = new("model_switch"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(PermissionModeSource left, PermissionModeSource right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionHistoryCompactRequestTrigger left, SessionHistoryCompactRequestTrigger right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PermissionModeSource left, PermissionModeSource right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionHistoryCompactRequestTrigger left, SessionHistoryCompactRequestTrigger right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PermissionModeSource other && Equals(other); + public override bool Equals(object? obj) => obj is SessionHistoryCompactRequestTrigger other && Equals(other); /// - public bool Equals(PermissionModeSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionHistoryCompactRequestTrigger other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39931,62 +45113,65 @@ public PermissionModeSource(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 PermissionModeSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionHistoryCompactRequestTrigger Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, PermissionModeSource value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionHistoryCompactRequestTrigger value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionModeSource)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionHistoryCompactRequestTrigger)); } } } -/// 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. +/// Aggregate file change represented by a rewind preview. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PermissionsModifyRulesScope : IEquatable +public readonly struct HistoryRewindChangeType : 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 PermissionsModifyRulesScope(string value) + public HistoryRewindChangeType(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; - /// Apply the rule change only to this session. - public static PermissionsModifyRulesScope Session { get; } = new("session"); + /// The discarded turns created the file. + public static HistoryRewindChangeType Created { get; } = new("created"); - /// Persist the rule change for this project location. - public static PermissionsModifyRulesScope Location { get; } = new("location"); + /// The discarded turns deleted the file. + public static HistoryRewindChangeType Deleted { get; } = new("deleted"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(PermissionsModifyRulesScope left, PermissionsModifyRulesScope right) => left.Equals(right); + /// The discarded turns modified the file. + public static HistoryRewindChangeType Modified { get; } = new("modified"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PermissionsModifyRulesScope left, PermissionsModifyRulesScope right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(HistoryRewindChangeType left, HistoryRewindChangeType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(HistoryRewindChangeType left, HistoryRewindChangeType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PermissionsModifyRulesScope other && Equals(other); + public override bool Equals(object? obj) => obj is HistoryRewindChangeType other && Equals(other); /// - public bool Equals(PermissionsModifyRulesScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(HistoryRewindChangeType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -39994,62 +45179,83 @@ public PermissionsModifyRulesScope(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 PermissionsModifyRulesScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override HistoryRewindChangeType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, PermissionsModifyRulesScope value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, HistoryRewindChangeType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsModifyRulesScope)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryRewindChangeType)); } } } -/// Whether the location is a git repo or directory. +/// Outcome of a rewind request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PermissionLocationType : IEquatable +public readonly struct HistoryRewindOutcome : 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 PermissionLocationType(string value) + public HistoryRewindOutcome(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; - /// The permission location is persisted at the git repository root. - public static PermissionLocationType Repo { get; } = new("repo"); + /// The requested rewind completed; reachable in either mode. + public static HistoryRewindOutcome Success { get; } = new("success"); - /// The permission location is persisted at the working directory. - public static PermissionLocationType Dir { get; } = new("dir"); + /// The session still has work that may mutate files or history; reachable in either mode. + public static HistoryRewindOutcome SessionBusy { get; } = new("session-busy"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(PermissionLocationType left, PermissionLocationType right) => left.Equals(right); + /// A conversation-and-files rewind was requested for a session that did not enable capture; conversation-only rewinds never produce this. + public static HistoryRewindOutcome FileChangeTrackingDisabled { get; } = new("file-change-tracking-disabled"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PermissionLocationType left, PermissionLocationType right) => !(left == right); + /// Remote-backed rewind routing is not supported; reachable in either mode. + public static HistoryRewindOutcome UnsupportedRemoteSession { get; } = new("unsupported-remote-session"); + + /// File restore failed and all applied file changes were rolled back; only conversation-and-files rewinds produce this. + public static HistoryRewindOutcome FilesRolledBack { get; } = new("files-rolled-back"); + + /// File restore failed and its rollback could not fully restore the pre-rewind state; only conversation-and-files rewinds produce this. + public static HistoryRewindOutcome RollbackIncomplete { get; } = new("rollback-incomplete"); + + /// Conversation truncation failed. In conversation-and-files mode any files that were restored are left in place because conversation history cannot be un-truncated; in conversation-only mode no files are restored. Consult restoredFiles for what, if anything, was applied. + public static HistoryRewindOutcome TruncationFailed { get; } = new("truncation-failed"); + + /// The conversation was rewound (and, in conversation-and-files mode, captured files were restored), but persisted checkpoints could not be cleaned up; reachable in either mode. + public static HistoryRewindOutcome CheckpointCleanupFailed { get; } = new("checkpoint-cleanup-failed"); + + /// Files and conversation were rewound, but obsolete file snapshots could not be removed; only conversation-and-files rewinds produce this. + public static HistoryRewindOutcome SnapshotPruneFailed { get; } = new("snapshot-prune-failed"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(HistoryRewindOutcome left, HistoryRewindOutcome right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(HistoryRewindOutcome left, HistoryRewindOutcome right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PermissionLocationType other && Equals(other); + public override bool Equals(object? obj) => obj is HistoryRewindOutcome other && Equals(other); /// - public bool Equals(PermissionLocationType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(HistoryRewindOutcome other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40057,65 +45263,62 @@ public PermissionLocationType(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 PermissionLocationType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override HistoryRewindOutcome Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, PermissionLocationType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, HistoryRewindOutcome value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionLocationType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryRewindOutcome)); } } } -/// The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot'). +/// Reason a captured file was not restored. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct MetadataSnapshotCurrentMode : IEquatable +public readonly struct HistoryFileRestoreSkipReason : 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 MetadataSnapshotCurrentMode(string value) + public HistoryFileRestoreSkipReason(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; - /// The agent is responding interactively to the user. - public static MetadataSnapshotCurrentMode Interactive { get; } = new("interactive"); - - /// The agent is preparing a plan before making changes. - public static MetadataSnapshotCurrentMode Plan { get; } = new("plan"); + /// The file changed after Copilot's last captured write. + public static HistoryFileRestoreSkipReason UserModified { get; } = new("user-modified"); - /// The agent is working autonomously toward task completion. - public static MetadataSnapshotCurrentMode Autopilot { get; } = new("autopilot"); + /// A faithful preimage was not captured. + public static HistoryFileRestoreSkipReason SkippedCapture { get; } = new("skipped-capture"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(MetadataSnapshotCurrentMode left, MetadataSnapshotCurrentMode right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(HistoryFileRestoreSkipReason left, HistoryFileRestoreSkipReason right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(MetadataSnapshotCurrentMode left, MetadataSnapshotCurrentMode right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(HistoryFileRestoreSkipReason left, HistoryFileRestoreSkipReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is MetadataSnapshotCurrentMode other && Equals(other); + public override bool Equals(object? obj) => obj is HistoryFileRestoreSkipReason other && Equals(other); /// - public bool Equals(MetadataSnapshotCurrentMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(HistoryFileRestoreSkipReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40123,62 +45326,62 @@ public MetadataSnapshotCurrentMode(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 MetadataSnapshotCurrentMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override HistoryFileRestoreSkipReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, MetadataSnapshotCurrentMode value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, HistoryFileRestoreSkipReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(MetadataSnapshotCurrentMode)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryFileRestoreSkipReason)); } } } -/// Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. +/// Scope of a rewind operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct MetadataSnapshotRemoteMetadataTaskType : IEquatable +public readonly struct HistoryRewindMode : 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 MetadataSnapshotRemoteMetadataTaskType(string value) + public HistoryRewindMode(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; - /// Remote task originated from Copilot Coding Agent. - public static MetadataSnapshotRemoteMetadataTaskType Cca { get; } = new("cca"); + /// Discard conversation events while leaving files unchanged. + public static HistoryRewindMode Conversation { get; } = new("conversation"); - /// Remote task originated from a CLI remote-session invocation. - public static MetadataSnapshotRemoteMetadataTaskType Cli { get; } = new("cli"); + /// Discard conversation events and restore captured files changed by those turns. + public static HistoryRewindMode ConversationAndFiles { get; } = new("conversation-and-files"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(MetadataSnapshotRemoteMetadataTaskType left, MetadataSnapshotRemoteMetadataTaskType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(HistoryRewindMode left, HistoryRewindMode right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(MetadataSnapshotRemoteMetadataTaskType left, MetadataSnapshotRemoteMetadataTaskType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(HistoryRewindMode left, HistoryRewindMode right) => !(left == right); /// - public override bool Equals(object? obj) => obj is MetadataSnapshotRemoteMetadataTaskType other && Equals(other); + public override bool Equals(object? obj) => obj is HistoryRewindMode other && Equals(other); /// - public bool Equals(MetadataSnapshotRemoteMetadataTaskType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(HistoryRewindMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40186,62 +45389,62 @@ public MetadataSnapshotRemoteMetadataTaskType(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 MetadataSnapshotRemoteMetadataTaskType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override HistoryRewindMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, MetadataSnapshotRemoteMetadataTaskType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, HistoryRewindMode value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(MetadataSnapshotRemoteMetadataTaskType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryRewindMode)); } } } -/// Repository host type, if known. +/// Whether this item is a queued user message or a queued slash command / model change. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct WorkspaceSummaryHostType : IEquatable +public readonly struct QueuePendingItemsKind : 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 WorkspaceSummaryHostType(string value) + public QueuePendingItemsKind(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; - /// Workspace summary repository is hosted on GitHub. - public static WorkspaceSummaryHostType GitHub { get; } = new("github"); + /// A queued user message. + public static QueuePendingItemsKind Message { get; } = new("message"); - /// Workspace summary repository is hosted on Azure DevOps. - public static WorkspaceSummaryHostType Ado { get; } = new("ado"); + /// A queued slash command or model-change command. + public static QueuePendingItemsKind Command { get; } = new("command"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(WorkspaceSummaryHostType left, WorkspaceSummaryHostType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(QueuePendingItemsKind left, QueuePendingItemsKind right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(WorkspaceSummaryHostType left, WorkspaceSummaryHostType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(QueuePendingItemsKind left, QueuePendingItemsKind right) => !(left == right); /// - public override bool Equals(object? obj) => obj is WorkspaceSummaryHostType other && Equals(other); + public override bool Equals(object? obj) => obj is QueuePendingItemsKind other && Equals(other); /// - public bool Equals(WorkspaceSummaryHostType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(QueuePendingItemsKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40249,62 +45452,62 @@ public WorkspaceSummaryHostType(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 WorkspaceSummaryHostType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override QueuePendingItemsKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, WorkspaceSummaryHostType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, QueuePendingItemsKind value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(WorkspaceSummaryHostType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(QueuePendingItemsKind)); } } } -/// Hosting platform type of the repository. +/// Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionWorkingDirectoryContextHostType : IEquatable +public readonly struct EventsAgentScope : 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 SessionWorkingDirectoryContextHostType(string value) + public EventsAgentScope(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; - /// The working directory repository is hosted on GitHub. - public static SessionWorkingDirectoryContextHostType GitHub { get; } = new("github"); + /// Return main-agent events and typed subagent lifecycle events. + public static EventsAgentScope Primary { get; } = new("primary"); - /// The working directory repository is hosted on Azure DevOps. - public static SessionWorkingDirectoryContextHostType Ado { get; } = new("ado"); + /// Return events from all agents. + public static EventsAgentScope All { get; } = new("all"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionWorkingDirectoryContextHostType left, SessionWorkingDirectoryContextHostType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(EventsAgentScope left, EventsAgentScope right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionWorkingDirectoryContextHostType left, SessionWorkingDirectoryContextHostType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(EventsAgentScope left, EventsAgentScope right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionWorkingDirectoryContextHostType other && Equals(other); + public override bool Equals(object? obj) => obj is EventsAgentScope other && Equals(other); /// - public bool Equals(SessionWorkingDirectoryContextHostType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(EventsAgentScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40312,113 +45515,80 @@ public SessionWorkingDirectoryContextHostType(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 SessionWorkingDirectoryContextHostType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override EventsAgentScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionWorkingDirectoryContextHostType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, EventsAgentScope value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionWorkingDirectoryContextHostType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(EventsAgentScope)); } } } -/// Rust-owned settings predicates exposed across the SDK boundary. Raw feature-flag names are intentionally not part of the contract. +/// Copilot plan tier used by the session quota projection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionSettingsPredicateName : IEquatable +public readonly struct SessionQuotaPlanTier : 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 SessionSettingsPredicateName(string value) + public SessionQuotaPlanTier(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; - /// Whether the security-tools feature flag enables security tool wiring. - public static SessionSettingsPredicateName SecurityToolsEnabled { get; } = new("securityToolsEnabled"); - - /// Whether third-party security tools should receive the security prompt. - public static SessionSettingsPredicateName ThirdPartySecurityPromptEnabled { get; } = new("thirdPartySecurityPromptEnabled"); - - /// Whether validation may run in parallel. - public static SessionSettingsPredicateName ParallelValidationEnabled { get; } = new("parallelValidationEnabled"); - - /// Whether runtime timing telemetry is enabled. - public static SessionSettingsPredicateName RuntimeTimingTelemetryEnabled { get; } = new("runtimeTimingTelemetryEnabled"); - - /// Whether the co-author hook is enabled. - public static SessionSettingsPredicateName CoAuthorHookEnabled { get; } = new("coAuthorHookEnabled"); - - /// Whether Chronicle integration is enabled. - public static SessionSettingsPredicateName ChronicleEnabled { get; } = new("chronicleEnabled"); - - /// Whether content-exclusion policy may self-fetch data. - public static SessionSettingsPredicateName ContentExclusionSelfFetchEnabled { get; } = new("contentExclusionSelfFetchEnabled"); - - /// Whether Claude Opus token-limit caps should be applied. - public static SessionSettingsPredicateName CapClaudeOpusTokenLimitsEnabled { get; } = new("capClaudeOpusTokenLimitsEnabled"); - - /// Whether code-review behavior is enabled. - public static SessionSettingsPredicateName CodeReviewFeatureEnabled { get; } = new("codeReviewFeatureEnabled"); - - /// Whether CCA should use the TypeScript autofind behavior. - public static SessionSettingsPredicateName CcaUseTsAutofindEnabled { get; } = new("ccaUseTsAutofindEnabled"); - - /// Whether the dependency checker is enabled. - public static SessionSettingsPredicateName DependencyCheckerEnabled { get; } = new("dependencyCheckerEnabled"); + /// Copilot Free. + public static SessionQuotaPlanTier Free { get; } = new("free"); - /// Whether the Dependabot checker is enabled. - public static SessionSettingsPredicateName DependabotCheckerEnabled { get; } = new("dependabotCheckerEnabled"); - - /// Whether the CodeQL checker is enabled. - public static SessionSettingsPredicateName CodeqlCheckerEnabled { get; } = new("codeqlCheckerEnabled"); + /// Copilot education entitlement. + public static SessionQuotaPlanTier Edu { get; } = new("edu"); - /// Whether trivial-change handling is enabled. - public static SessionSettingsPredicateName TrivialChangeEnabled { get; } = new("trivialChangeEnabled"); + /// Copilot Pro. + public static SessionQuotaPlanTier Pro { get; } = new("pro"); - /// Whether trivial-change skip behavior is enabled. - public static SessionSettingsPredicateName TrivialChangeSkipEnabled { get; } = new("trivialChangeSkipEnabled"); + /// Copilot Pro+. + public static SessionQuotaPlanTier ProPlus { get; } = new("pro_plus"); - /// Whether trivial-change handling is enabled for code review. - public static SessionSettingsPredicateName TrivialChangeEnabledForCodeReview { get; } = new("trivialChangeEnabledForCodeReview"); + /// Copilot Business. + public static SessionQuotaPlanTier Business { get; } = new("business"); - /// Whether trivial-change skip behavior is enabled for code review. - public static SessionSettingsPredicateName TrivialChangeSkipEnabledForCodeReview { get; } = new("trivialChangeSkipEnabledForCodeReview"); + /// Copilot Enterprise. + public static SessionQuotaPlanTier Enterprise { get; } = new("enterprise"); - /// Whether trivial-change handling is enabled for a specific tool. - public static SessionSettingsPredicateName TrivialChangeEnabledForTool { get; } = new("trivialChangeEnabledForTool"); + /// Copilot Max. + public static SessionQuotaPlanTier Max { get; } = new("max"); - /// Whether trivial-change skip behavior is enabled for a specific tool. - public static SessionSettingsPredicateName TrivialChangeSkipEnabledForTool { get; } = new("trivialChangeSkipEnabledForTool"); + /// The account's plan tier is not known. + public static SessionQuotaPlanTier Unknown { get; } = new("unknown"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionSettingsPredicateName left, SessionSettingsPredicateName right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionQuotaPlanTier left, SessionQuotaPlanTier right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionSettingsPredicateName left, SessionSettingsPredicateName right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionQuotaPlanTier left, SessionQuotaPlanTier right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionSettingsPredicateName other && Equals(other); + public override bool Equals(object? obj) => obj is SessionQuotaPlanTier other && Equals(other); /// - public bool Equals(SessionSettingsPredicateName other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionQuotaPlanTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40426,65 +45596,62 @@ public SessionSettingsPredicateName(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 SessionSettingsPredicateName Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionQuotaPlanTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionSettingsPredicateName value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionQuotaPlanTier value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionSettingsPredicateName)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionQuotaPlanTier)); } } } -/// Signal to send (default: SIGTERM). +/// Client population used for the prediction baseline. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ShellKillSignal : IEquatable +public readonly struct SessionLimitPredictionClientType : 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 ShellKillSignal(string value) + public SessionLimitPredictionClientType(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; - /// Request graceful process termination. - public static ShellKillSignal SIGTERM { get; } = new("SIGTERM"); - - /// Forcefully terminate the process. - public static ShellKillSignal SIGKILL { get; } = new("SIGKILL"); + /// Interactive CLI sessions where a user can accept, edit, or top up the limit. + public static SessionLimitPredictionClientType CliInteractive { get; } = new("cli-interactive"); - /// Send an interrupt signal to the process. - public static ShellKillSignal SIGINT { get; } = new("SIGINT"); + /// Prompt/non-interactive CLI sessions where the initial limit must cover more of the run. + public static SessionLimitPredictionClientType CliPrompt { get; } = new("cli-prompt"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ShellKillSignal left, ShellKillSignal right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionLimitPredictionClientType left, SessionLimitPredictionClientType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ShellKillSignal left, ShellKillSignal right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionLimitPredictionClientType left, SessionLimitPredictionClientType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ShellKillSignal other && Equals(other); + public override bool Equals(object? obj) => obj is SessionLimitPredictionClientType other && Equals(other); /// - public bool Equals(ShellKillSignal other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionLimitPredictionClientType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40492,61 +45659,68 @@ public ShellKillSignal(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 ShellKillSignal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionLimitPredictionClientType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ShellKillSignal value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionLimitPredictionClientType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShellKillSignal)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionClientType)); } } } -/// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). +/// Semantic usage tier used for a recommended cap or additional headroom. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionHistoryCompactRequestTrigger : IEquatable +public readonly struct SessionLimitPredictionTier : 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 SessionHistoryCompactRequestTrigger(string value) + public SessionLimitPredictionTier(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; - /// User-requested compaction, e.g. the /compact command or a direct history.compact call. - public static SessionHistoryCompactRequestTrigger Manual { get; } = new("manual"); + /// Recommended starting tier. + public static SessionLimitPredictionTier Recommended { get; } = new("recommended"); - /// Compaction requested while switching to a model with a smaller context window. - public static SessionHistoryCompactRequestTrigger ModelSwitch { get; } = new("model_switch"); + /// Additional headroom for longer-running sessions. + public static SessionLimitPredictionTier AdditionalHeadroom { get; } = new("additional_headroom"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionHistoryCompactRequestTrigger left, SessionHistoryCompactRequestTrigger right) => left.Equals(right); + /// Generous headroom for unusually high usage. + public static SessionLimitPredictionTier GenerousHeadroom { get; } = new("generous_headroom"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionHistoryCompactRequestTrigger left, SessionHistoryCompactRequestTrigger right) => !(left == right); + /// Maximum available headroom tier. + public static SessionLimitPredictionTier MaximumHeadroom { get; } = new("maximum_headroom"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionLimitPredictionTier left, SessionLimitPredictionTier right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionLimitPredictionTier left, SessionLimitPredictionTier right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionHistoryCompactRequestTrigger other && Equals(other); + public override bool Equals(object? obj) => obj is SessionLimitPredictionTier other && Equals(other); /// - public bool Equals(SessionHistoryCompactRequestTrigger other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionLimitPredictionTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40554,65 +45728,65 @@ public SessionHistoryCompactRequestTrigger(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 SessionHistoryCompactRequestTrigger Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionLimitPredictionTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionHistoryCompactRequestTrigger value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionLimitPredictionTier value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionHistoryCompactRequestTrigger)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionTier)); } } } -/// Aggregate file change represented by a rewind preview. +/// Baseline fallback level used to create the prediction. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct HistoryRewindChangeType : IEquatable +public readonly struct SessionLimitPredictionSource : 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 HistoryRewindChangeType(string value) + public SessionLimitPredictionSource(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; - /// The discarded turns created the file. - public static HistoryRewindChangeType Created { get; } = new("created"); + /// The prediction used the exact resolved model's baseline cell. + public static SessionLimitPredictionSource Model { get; } = new("model"); - /// The discarded turns deleted the file. - public static HistoryRewindChangeType Deleted { get; } = new("deleted"); + /// The exact model was unavailable, so the prediction used the model family's baseline cell. + public static SessionLimitPredictionSource Family { get; } = new("family"); - /// The discarded turns modified the file. - public static HistoryRewindChangeType Modified { get; } = new("modified"); + /// No model or family cell was available, so the prediction used the global client-type baseline cell. + public static SessionLimitPredictionSource Global { get; } = new("global"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(HistoryRewindChangeType left, HistoryRewindChangeType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionLimitPredictionSource left, SessionLimitPredictionSource right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(HistoryRewindChangeType left, HistoryRewindChangeType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionLimitPredictionSource left, SessionLimitPredictionSource right) => !(left == right); /// - public override bool Equals(object? obj) => obj is HistoryRewindChangeType other && Equals(other); + public override bool Equals(object? obj) => obj is SessionLimitPredictionSource other && Equals(other); /// - public bool Equals(HistoryRewindChangeType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionLimitPredictionSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40620,83 +45794,62 @@ public HistoryRewindChangeType(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 HistoryRewindChangeType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionLimitPredictionSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, HistoryRewindChangeType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionLimitPredictionSource value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryRewindChangeType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionSource)); } } } -/// Outcome of a rewind request. +/// Reason a prediction could not be computed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct HistoryRewindOutcome : IEquatable +public readonly struct SessionLimitPredictionUnavailableReason : 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 HistoryRewindOutcome(string value) + public SessionLimitPredictionUnavailableReason(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; - /// The requested rewind completed; reachable in either mode. - public static HistoryRewindOutcome Success { get; } = new("success"); - - /// The session still has work that may mutate files or history; reachable in either mode. - public static HistoryRewindOutcome SessionBusy { get; } = new("session-busy"); - - /// A conversation-and-files rewind was requested for a session that did not enable capture; conversation-only rewinds never produce this. - public static HistoryRewindOutcome FileChangeTrackingDisabled { get; } = new("file-change-tracking-disabled"); - - /// Remote-backed rewind routing is not supported; reachable in either mode. - public static HistoryRewindOutcome UnsupportedRemoteSession { get; } = new("unsupported-remote-session"); - - /// File restore failed and all applied file changes were rolled back; only conversation-and-files rewinds produce this. - public static HistoryRewindOutcome FilesRolledBack { get; } = new("files-rolled-back"); - - /// File restore failed and its rollback could not fully restore the pre-rewind state; only conversation-and-files rewinds produce this. - public static HistoryRewindOutcome RollbackIncomplete { get; } = new("rollback-incomplete"); - - /// Conversation truncation failed. In conversation-and-files mode any files that were restored are left in place because conversation history cannot be un-truncated; in conversation-only mode no files are restored. Consult restoredFiles for what, if anything, was applied. - public static HistoryRewindOutcome TruncationFailed { get; } = new("truncation-failed"); - - /// The conversation was rewound (and, in conversation-and-files mode, captured files were restored), but persisted checkpoints could not be cleaned up; reachable in either mode. - public static HistoryRewindOutcome CheckpointCleanupFailed { get; } = new("checkpoint-cleanup-failed"); + /// The current model is auto and has not resolved to a concrete model yet. + public static SessionLimitPredictionUnavailableReason AutoUnresolved { get; } = new("auto_unresolved"); - /// Files and conversation were rewound, but obsolete file snapshots could not be removed; only conversation-and-files rewinds produce this. - public static HistoryRewindOutcome SnapshotPruneFailed { get; } = new("snapshot-prune-failed"); + /// No model was provided and the session does not currently have a selected model. + public static SessionLimitPredictionUnavailableReason NoModel { get; } = new("no_model"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(HistoryRewindOutcome left, HistoryRewindOutcome right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionLimitPredictionUnavailableReason left, SessionLimitPredictionUnavailableReason right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(HistoryRewindOutcome left, HistoryRewindOutcome right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionLimitPredictionUnavailableReason left, SessionLimitPredictionUnavailableReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is HistoryRewindOutcome other && Equals(other); + public override bool Equals(object? obj) => obj is SessionLimitPredictionUnavailableReason other && Equals(other); /// - public bool Equals(HistoryRewindOutcome other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionLimitPredictionUnavailableReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40704,62 +45857,65 @@ public HistoryRewindOutcome(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 HistoryRewindOutcome Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionLimitPredictionUnavailableReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, HistoryRewindOutcome value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionLimitPredictionUnavailableReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryRewindOutcome)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionUnavailableReason)); } } } -/// Reason a captured file was not restored. +/// Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct HistoryFileRestoreSkipReason : IEquatable +public readonly struct RemoteSessionMode : 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 HistoryFileRestoreSkipReason(string value) + public RemoteSessionMode(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; - /// The file changed after Copilot's last captured write. - public static HistoryFileRestoreSkipReason UserModified { get; } = new("user-modified"); + /// Disable remote session export and steering. + public static RemoteSessionMode Off { get; } = new("off"); - /// A faithful preimage was not captured. - public static HistoryFileRestoreSkipReason SkippedCapture { get; } = new("skipped-capture"); + /// Export session events to GitHub without enabling remote steering. + public static RemoteSessionMode Export { get; } = new("export"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(HistoryFileRestoreSkipReason left, HistoryFileRestoreSkipReason right) => left.Equals(right); + /// Enable both remote session export and remote steering. + public static RemoteSessionMode On { get; } = new("on"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(HistoryFileRestoreSkipReason left, HistoryFileRestoreSkipReason right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(RemoteSessionMode left, RemoteSessionMode right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(RemoteSessionMode left, RemoteSessionMode right) => !(left == right); /// - public override bool Equals(object? obj) => obj is HistoryFileRestoreSkipReason other && Equals(other); + public override bool Equals(object? obj) => obj is RemoteSessionMode other && Equals(other); /// - public bool Equals(HistoryFileRestoreSkipReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(RemoteSessionMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40767,62 +45923,62 @@ public HistoryFileRestoreSkipReason(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 HistoryFileRestoreSkipReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override RemoteSessionMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, HistoryFileRestoreSkipReason value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, RemoteSessionMode value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryFileRestoreSkipReason)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RemoteSessionMode)); } } } -/// Scope of a rewind operation. +/// Sharing status for a synced session. "repo" makes the session visible to anyone with read access to the repository; "unshared" restricts it to the creator and collaborators. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct HistoryRewindMode : IEquatable +public readonly struct SessionVisibilityStatus : 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 HistoryRewindMode(string value) + public SessionVisibilityStatus(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; - /// Discard conversation events while leaving files unchanged. - public static HistoryRewindMode Conversation { get; } = new("conversation"); + /// The session is visible to repository readers. + public static SessionVisibilityStatus Repo { get; } = new("repo"); - /// Discard conversation events and restore captured files changed by those turns. - public static HistoryRewindMode ConversationAndFiles { get; } = new("conversation-and-files"); + /// The session is restricted to its creator and collaborators. + public static SessionVisibilityStatus Unshared { get; } = new("unshared"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(HistoryRewindMode left, HistoryRewindMode right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionVisibilityStatus left, SessionVisibilityStatus right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(HistoryRewindMode left, HistoryRewindMode right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionVisibilityStatus left, SessionVisibilityStatus right) => !(left == right); /// - public override bool Equals(object? obj) => obj is HistoryRewindMode other && Equals(other); + public override bool Equals(object? obj) => obj is SessionVisibilityStatus other && Equals(other); /// - public bool Equals(HistoryRewindMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionVisibilityStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40830,62 +45986,62 @@ public HistoryRewindMode(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 HistoryRewindMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionVisibilityStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, HistoryRewindMode value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionVisibilityStatus value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HistoryRewindMode)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionVisibilityStatus)); } } } -/// Whether this item is a queued user message or a queued slash command / model change. +/// Why the runtime requests client-task cancellation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct QueuePendingItemsKind : IEquatable +public readonly struct ClientTaskCancelReason : 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 QueuePendingItemsKind(string value) + public ClientTaskCancelReason(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; - /// A queued user message. - public static QueuePendingItemsKind Message { get; } = new("message"); + /// A caller requested task cancellation. + public static ClientTaskCancelReason CancelRequested { get; } = new("cancel_requested"); - /// A queued slash command or model-change command. - public static QueuePendingItemsKind Command { get; } = new("command"); + /// The session is shutting down. + public static ClientTaskCancelReason SessionShutdown { get; } = new("session_shutdown"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(QueuePendingItemsKind left, QueuePendingItemsKind right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ClientTaskCancelReason left, ClientTaskCancelReason right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(QueuePendingItemsKind left, QueuePendingItemsKind right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ClientTaskCancelReason left, ClientTaskCancelReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is QueuePendingItemsKind other && Equals(other); + public override bool Equals(object? obj) => obj is ClientTaskCancelReason other && Equals(other); /// - public bool Equals(QueuePendingItemsKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ClientTaskCancelReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40893,62 +46049,62 @@ public QueuePendingItemsKind(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 QueuePendingItemsKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ClientTaskCancelReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, QueuePendingItemsKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ClientTaskCancelReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(QueuePendingItemsKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ClientTaskCancelReason)); } } } -/// Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. +/// Error classification. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct EventsAgentScope : IEquatable +public readonly struct SessionFsErrorCode : 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 EventsAgentScope(string value) + public SessionFsErrorCode(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; - /// Return main-agent events and typed subagent lifecycle events. - public static EventsAgentScope Primary { get; } = new("primary"); + /// The requested path does not exist. + public static SessionFsErrorCode ENOENT { get; } = new("ENOENT"); - /// Return events from all agents. - public static EventsAgentScope All { get; } = new("all"); + /// The filesystem operation failed for an unspecified reason. + public static SessionFsErrorCode UNKNOWN { get; } = new("UNKNOWN"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(EventsAgentScope left, EventsAgentScope right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsErrorCode left, SessionFsErrorCode right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(EventsAgentScope left, EventsAgentScope right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsErrorCode left, SessionFsErrorCode right) => !(left == right); /// - public override bool Equals(object? obj) => obj is EventsAgentScope other && Equals(other); + public override bool Equals(object? obj) => obj is SessionFsErrorCode other && Equals(other); /// - public bool Equals(EventsAgentScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionFsErrorCode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -40956,62 +46112,62 @@ public EventsAgentScope(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 EventsAgentScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionFsErrorCode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, EventsAgentScope value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionFsErrorCode value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(EventsAgentScope)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsErrorCode)); } } } -/// Client population used for the prediction baseline. +/// Entry type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionLimitPredictionClientType : IEquatable +public readonly struct SessionFsReaddirWithTypesEntryType : 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 SessionLimitPredictionClientType(string value) + public SessionFsReaddirWithTypesEntryType(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; - /// Interactive CLI sessions where a user can accept, edit, or top up the limit. - public static SessionLimitPredictionClientType CliInteractive { get; } = new("cli-interactive"); + /// The entry is a file. + public static SessionFsReaddirWithTypesEntryType File { get; } = new("file"); - /// Prompt/non-interactive CLI sessions where the initial limit must cover more of the run. - public static SessionLimitPredictionClientType CliPrompt { get; } = new("cli-prompt"); + /// The entry is a directory. + public static SessionFsReaddirWithTypesEntryType Directory { get; } = new("directory"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionLimitPredictionClientType left, SessionLimitPredictionClientType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionLimitPredictionClientType left, SessionLimitPredictionClientType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionLimitPredictionClientType other && Equals(other); + public override bool Equals(object? obj) => obj is SessionFsReaddirWithTypesEntryType other && Equals(other); /// - public bool Equals(SessionLimitPredictionClientType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionFsReaddirWithTypesEntryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -41019,68 +46175,65 @@ public SessionLimitPredictionClientType(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 SessionLimitPredictionClientType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionFsReaddirWithTypesEntryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionLimitPredictionClientType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionFsReaddirWithTypesEntryType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionClientType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsReaddirWithTypesEntryType)); } } } -/// Semantic usage tier used for a recommended cap or additional headroom. +/// 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(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionLimitPredictionTier : IEquatable +public readonly struct SessionFsSqliteQueryType : 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 SessionLimitPredictionTier(string value) + public SessionFsSqliteQueryType(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; - /// Recommended starting tier. - public static SessionLimitPredictionTier Recommended { get; } = new("recommended"); - - /// Additional headroom for longer-running sessions. - public static SessionLimitPredictionTier AdditionalHeadroom { get; } = new("additional_headroom"); + /// Execute DDL or multi-statement SQL without returning rows. + public static SessionFsSqliteQueryType Exec { get; } = new("exec"); - /// Generous headroom for unusually high usage. - public static SessionLimitPredictionTier GenerousHeadroom { get; } = new("generous_headroom"); + /// Execute a SELECT-style query and return rows. + public static SessionFsSqliteQueryType Query { get; } = new("query"); - /// Maximum available headroom tier. - public static SessionLimitPredictionTier MaximumHeadroom { get; } = new("maximum_headroom"); + /// Execute INSERT, UPDATE, or DELETE SQL and return affected-row metadata. + public static SessionFsSqliteQueryType Run { get; } = new("run"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionLimitPredictionTier left, SessionLimitPredictionTier right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionLimitPredictionTier left, SessionLimitPredictionTier right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionLimitPredictionTier other && Equals(other); + public override bool Equals(object? obj) => obj is SessionFsSqliteQueryType other && Equals(other); /// - public bool Equals(SessionLimitPredictionTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionFsSqliteQueryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -41088,65 +46241,65 @@ public SessionLimitPredictionTier(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 SessionLimitPredictionTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionFsSqliteQueryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionLimitPredictionTier value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionFsSqliteQueryType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionTier)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteQueryType)); } } } -/// Baseline fallback level used to create the prediction. +/// SQLite transaction failure classification. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionLimitPredictionSource : IEquatable +public readonly struct SessionFsSqliteTransactionErrorClass : 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 SessionLimitPredictionSource(string value) + public SessionFsSqliteTransactionErrorClass(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; - /// The prediction used the exact resolved model's baseline cell. - public static SessionLimitPredictionSource Model { get; } = new("model"); + /// SQLite reported BUSY or LOCKED before commit; the transaction was rolled back and may be retried. + public static SessionFsSqliteTransactionErrorClass BusyOrLocked { get; } = new("busyOrLocked"); - /// The exact model was unavailable, so the prediction used the model family's baseline cell. - public static SessionLimitPredictionSource Family { get; } = new("family"); + /// The statement, database, or provider failed definitively and must not be retried automatically. + public static SessionFsSqliteTransactionErrorClass Fatal { get; } = new("fatal"); - /// No model or family cell was available, so the prediction used the global client-type baseline cell. - public static SessionLimitPredictionSource Global { get; } = new("global"); + /// The transport failed after the provider may have committed; retrying could duplicate effects. + public static SessionFsSqliteTransactionErrorClass PostCommitAmbiguous { get; } = new("postCommitAmbiguous"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionLimitPredictionSource left, SessionLimitPredictionSource right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionLimitPredictionSource left, SessionLimitPredictionSource right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionLimitPredictionSource other && Equals(other); + public override bool Equals(object? obj) => obj is SessionFsSqliteTransactionErrorClass other && Equals(other); /// - public bool Equals(SessionLimitPredictionSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SessionFsSqliteTransactionErrorClass other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -41154,62 +46307,68 @@ public SessionLimitPredictionSource(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 SessionLimitPredictionSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SessionFsSqliteTransactionErrorClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionLimitPredictionSource value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SessionFsSqliteTransactionErrorClass value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionSource)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteTransactionErrorClass)); } } } -/// Reason a prediction could not be computed. +/// Defines the allowed values. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionLimitPredictionUnavailableReason : IEquatable +public readonly struct HostExitReason : 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 SessionLimitPredictionUnavailableReason(string value) + public HostExitReason(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; - /// The current model is auto and has not resolved to a concrete model yet. - public static SessionLimitPredictionUnavailableReason AutoUnresolved { get; } = new("auto_unresolved"); + /// The owner requested disposal. + public static HostExitReason Disposed { get; } = new("disposed"); - /// No model was provided and the session does not currently have a selected model. - public static SessionLimitPredictionUnavailableReason NoModel { get; } = new("no_model"); + /// The hosting task or its SDK transport exited; this does not mean the runtime process exited. + public static HostExitReason Exited { get; } = new("exited"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionLimitPredictionUnavailableReason left, SessionLimitPredictionUnavailableReason right) => left.Equals(right); + /// The owning SDK connection disconnected. + public static HostExitReason OwnerDisconnected { get; } = new("ownerDisconnected"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionLimitPredictionUnavailableReason left, SessionLimitPredictionUnavailableReason right) => !(left == right); + /// The runtime is shutting down. + public static HostExitReason RuntimeShutdown { get; } = new("runtimeShutdown"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(HostExitReason left, HostExitReason right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(HostExitReason left, HostExitReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionLimitPredictionUnavailableReason other && Equals(other); + public override bool Equals(object? obj) => obj is HostExitReason other && Equals(other); /// - public bool Equals(SessionLimitPredictionUnavailableReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(HostExitReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -41217,65 +46376,62 @@ public SessionLimitPredictionUnavailableReason(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 SessionLimitPredictionUnavailableReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override HostExitReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionLimitPredictionUnavailableReason value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, HostExitReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionLimitPredictionUnavailableReason)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HostExitReason)); } } } -/// Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. +/// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct RemoteSessionMode : IEquatable +public readonly struct LlmInferenceHttpRequestStartTransport : 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 RemoteSessionMode(string value) + public LlmInferenceHttpRequestStartTransport(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; - /// Disable remote session export and steering. - public static RemoteSessionMode Off { get; } = new("off"); - - /// Export session events to GitHub without enabling remote steering. - public static RemoteSessionMode Export { get; } = new("export"); + /// Plain HTTP or SSE response. Each body chunk is an opaque byte range; the response is a status line, headers, and a (possibly streamed) body. + public static LlmInferenceHttpRequestStartTransport Http { get; } = new("http"); - /// Enable both remote session export and remote steering. - public static RemoteSessionMode On { get; } = new("on"); + /// Full-duplex WebSocket channel. Each body chunk maps to exactly one WebSocket message and the `binary` flag distinguishes text from binary frames; request and response chunks flow concurrently. + public static LlmInferenceHttpRequestStartTransport Websocket { get; } = new("websocket"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(RemoteSessionMode left, RemoteSessionMode right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(RemoteSessionMode left, RemoteSessionMode right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => !(left == right); /// - public override bool Equals(object? obj) => obj is RemoteSessionMode other && Equals(other); + public override bool Equals(object? obj) => obj is LlmInferenceHttpRequestStartTransport other && Equals(other); /// - public bool Equals(RemoteSessionMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(LlmInferenceHttpRequestStartTransport other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -41283,62 +46439,62 @@ public RemoteSessionMode(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 RemoteSessionMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override LlmInferenceHttpRequestStartTransport Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, RemoteSessionMode value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, LlmInferenceHttpRequestStartTransport value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RemoteSessionMode)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(LlmInferenceHttpRequestStartTransport)); } } } -/// Sharing status for a synced session. "repo" makes the session visible to anyone with read access to the repository; "unshared" restricts it to the creator and collaborators. +/// Why the runtime is requesting a GitHub credential. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionVisibilityStatus : IEquatable +public readonly struct GitHubTokenAcquireReason : 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 SessionVisibilityStatus(string value) + public GitHubTokenAcquireReason(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; - /// The session is visible to repository readers. - public static SessionVisibilityStatus Repo { get; } = new("repo"); + /// The runtime is acquiring the registration's first credential. + public static GitHubTokenAcquireReason Initial { get; } = new("initial"); - /// The session is restricted to its creator and collaborators. - public static SessionVisibilityStatus Unshared { get; } = new("unshared"); + /// The runtime is replacing a credential that is approaching expiry. + public static GitHubTokenAcquireReason Refresh { get; } = new("refresh"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionVisibilityStatus left, SessionVisibilityStatus right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionVisibilityStatus left, SessionVisibilityStatus right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionVisibilityStatus other && Equals(other); + public override bool Equals(object? obj) => obj is GitHubTokenAcquireReason other && Equals(other); /// - public bool Equals(SessionVisibilityStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(GitHubTokenAcquireReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -41346,62 +46502,65 @@ public SessionVisibilityStatus(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 SessionVisibilityStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override GitHubTokenAcquireReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionVisibilityStatus value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, GitHubTokenAcquireReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionVisibilityStatus)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(GitHubTokenAcquireReason)); } } } -/// Why the runtime requests client-task cancellation. +/// Explicit user decisions, never inferred from a permission grant or model response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ClientTaskCancelReason : IEquatable +public readonly struct InstallationDecision : 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 ClientTaskCancelReason(string value) + public InstallationDecision(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; - /// A caller requested task cancellation. - public static ClientTaskCancelReason CancelRequested { get; } = new("cancel_requested"); + /// The user explicitly approved the exact review on this request. + public static InstallationDecision Confirm { get; } = new("confirm"); - /// The session is shutting down. - public static ClientTaskCancelReason SessionShutdown { get; } = new("session_shutdown"); + /// The user declined the reviewed operation. + public static InstallationDecision Decline { get; } = new("decline"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ClientTaskCancelReason left, ClientTaskCancelReason right) => left.Equals(right); + /// The user cancelled the pending decision without granting consent. + public static InstallationDecision Cancel { get; } = new("cancel"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ClientTaskCancelReason left, ClientTaskCancelReason right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstallationDecision left, InstallationDecision right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstallationDecision left, InstallationDecision right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ClientTaskCancelReason other && Equals(other); + public override bool Equals(object? obj) => obj is InstallationDecision other && Equals(other); /// - public bool Equals(ClientTaskCancelReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(InstallationDecision other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -41409,724 +46568,1436 @@ public ClientTaskCancelReason(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 ClientTaskCancelReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override InstallationDecision Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ClientTaskCancelReason value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, InstallationDecision value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ClientTaskCancelReason)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstallationDecision)); } } } -/// Error classification. +/// Provides server-scoped RPC methods (no session required). +public sealed class ServerRpc +{ + private readonly JsonRpc _rpc; + + internal ServerRpc(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Checks server responsiveness and returns protocol information. + /// Optional message to echo back. + /// The to monitor for cancellation requests. The default is . + /// Server liveness response, including the echoed message, current server timestamp, and protocol version. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public async Task PingAsync(string? message = null, CancellationToken cancellationToken = default) + { + var request = new PingRequest { Message = message }; + return await CopilotClient.InvokeRpcAsync(_rpc, "ping", [request], cancellationToken); + } + + /// Performs the SDK server connection handshake and validates the optional connection token. Marked internal because this is JSON-RPC transport plumbing invoked automatically by an SDK client's own `connect()` wrapper, not a user-facing method. Stays internal as long as the SDK client owns the handshake; would only become public if the SDK ever exposed the raw schema surface to consumers without a connection wrapper. + /// Opt this connection in to GitHub telemetry forwarding for its lifetime. When set, the runtime forwards this host's telemetry across all its sessions, its sessionless events, and explicitly process-wide events over the `gitHubTelemetry.event` notification. Connections intentionally sharing one server receive that server's events; independently embedded runtime hosts do not receive each other's host-owned events. Regular events are also written to the runtime's normal GitHub/CTS path (dual-write); host-only compatibility events are forward-only and intentionally skip that path. Intended for first-party hosts that re-emit the events into their own telemetry stores. Both unrestricted and restricted events are forwarded, each tagged with a `restricted` discriminator; a backstop drops restricted events when restricted telemetry is disabled — using the process-global gate for ordinary events and an explicit session-scoped decision for host-only events. + /// Identity of the integrating host. Optional; omit it to keep the default attribution. + /// Task kinds this connection can decode when observing session tasks. Omit to retain agent and shell compatibility. + /// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN. + /// The to monitor for cancellation requests. The default is . + /// Handshake result reporting the server's protocol version and package version on success. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + internal async Task ConnectAsync(bool? enableGitHubTelemetryForwarding = null, ConnectClientInfo? clientInfo = null, IList? supportedTaskKinds = null, string? token = null, CancellationToken cancellationToken = default) + { + var request = new ConnectRequest { EnableGitHubTelemetryForwarding = enableGitHubTelemetryForwarding, ClientInfo = clientInfo, SupportedTaskKinds = supportedTaskKinds, Token = token }; + return await CopilotClient.InvokeRpcAsync(_rpc, "connect", [request], cancellationToken); + } + + /// Registers the calling SDK client as the per-entrypoint extension launch provider. Call before creating any sessions. When omitted, the runtime uses its built-in extension launcher. + /// The to monitor for cancellation requests. The default is . + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public async Task RegisterExtensionLaunchProviderAsync(CancellationToken cancellationToken = default) + { + await CopilotClient.InvokeRpcAsync(_rpc, "registerExtensionLaunchProvider", [], cancellationToken); + } + + /// Sandbox APIs. + public ServerSandboxApi Sandbox => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Persistence APIs. + public ServerPersistenceApi Persistence => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// User APIs. + public ServerUserApi User => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Repo APIs. + public ServerRepoApi Repo => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// FeatureFlags APIs. + public ServerFeatureFlagsApi FeatureFlags => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Permissions APIs. + public ServerPermissionsApi Permissions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// ManagedSettings APIs. + public ServerManagedSettingsApi ManagedSettings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Environments APIs. + public ServerEnvironmentsApi Environments => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Host APIs. + public ServerHostApi Host => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Hooks APIs. + public ServerHooksApi Hooks => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Models APIs. + public ServerModelsApi Models => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Tools APIs. + public ServerToolsApi Tools => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Account APIs. + public ServerAccountApi Account => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Secrets APIs. + public ServerSecretsApi Secrets => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Mcp APIs. + public ServerMcpApi Mcp => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Extensions APIs. + public ServerExtensionsApi Extensions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Instructions APIs. + public ServerInstructionsApi Instructions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Skills APIs. + public ServerSkillsApi Skills => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Catalog APIs. + public ServerCatalogApi Catalog => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Plugins APIs. + public ServerPluginsApi Plugins => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Agents APIs. + public ServerAgentsApi Agents => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// GlobalState APIs. + public ServerGlobalStateApi GlobalState => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Commands APIs. + public ServerCommandsApi Commands => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// GitHubRepository APIs. + public ServerGitHubRepositoryApi GitHubRepository => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// GitHubOwners APIs. + public ServerGitHubOwnersApi GitHubOwners => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Git APIs. + public ServerGitApi Git => + field ?? + 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 ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// LlmInference APIs. + public ServerLlmInferenceApi LlmInference => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Sessions APIs. + public ServerSessionsApi Sessions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// AgentRegistry APIs. + public ServerAgentRegistryApi AgentRegistry => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Connectors APIs. + public ServerConnectorsApi Connectors => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} + +/// Provides server-scoped Sandbox APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerSandboxApi +{ + private readonly JsonRpc _rpc; + + internal ServerSandboxApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Raises a user's sandbox settings to an administrator's managed sandbox floor and returns the result a session should actually run under. The floor can only tighten: an enterprise force-on is reflected even when the user's own `enabled` is false, and a user cannot lower a setting the floor raised. The result is normalized through the declared sandbox shape, so a key reorder or an undeclared passthrough key is not mistaken for a policy change by callers that diff two results. A host must call this rather than merge the two layers itself, because reimplementing the direction of the fold is what turns an administrator's floor into a suggestion. + /// The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. + /// The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. + /// The to monitor for cancellation requests. The default is . + /// The user's sandbox settings raised to the managed floor. + internal async Task ResolveFlooredConfigAsync(object? userSandbox = null, object? managedSandbox = null, CancellationToken cancellationToken = default) + { + var request = new SandboxResolveFlooredConfigParams { UserSandbox = CopilotClient.ToJsonElementForWire(userSandbox), ManagedSandbox = CopilotClient.ToJsonElementForWire(managedSandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.resolveFlooredConfig", [request], cancellationToken); + } + + /// Builds the effective filesystem policy one `@`-file picker checks its suggestions against, so Git discovery and grant canonicalization run once for the picker's lifetime instead of on every debounced keystroke. Returns no policy when the sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant list itself, because the picker's grants are narrower than a file tool's — the same path a built-in tool may read can be one the picker must not offer. + /// The session's working directory. Git discovery and grant canonicalization are resolved against it. + /// The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. + /// The to monitor for cancellation requests. The default is . + /// The prepared file-picker policy, or none when the sandbox is disabled. + internal async Task PreparePickerPolicyAsync(string cwd, object? sandbox = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(cwd); + + var request = new SandboxPreparePickerPolicyParams { Cwd = cwd, Sandbox = CopilotClient.ToJsonElementForWire(sandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.preparePickerPolicy", [request], cancellationToken); + } + + /// Checks a batch of `@`-file picker suggestions against a policy prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, positionally aligned with the request. Batched deliberately: each check canonicalizes a path component-by-component through the real filesystem, so one call amortizes that over a single hop rather than dozens while the user types. A directory the policy does not itself allow can still be kept as a waypoint to an allowed subtree. An absent policy keeps every candidate. + /// The candidates to check, in the order the answers are returned. + /// The session's working directory, matching the one the policy was prepared from. + /// The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. + /// The to monitor for cancellation requests. The default is . + /// Per-candidate allow decisions, positionally aligned with the request. + internal async Task FilterPickerCandidatesAsync(IList candidates, string cwd, object? sandbox = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(candidates); + ArgumentNullException.ThrowIfNull(cwd); + + var request = new SandboxFilterPickerCandidatesParams { Candidates = candidates, Cwd = cwd, Sandbox = CopilotClient.ToJsonElementForWire(sandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.filterPickerCandidates", [request], cancellationToken); + } + + /// The sandbox a single named feature actually launches under, which is not the same as the session's sandbox. A feature is routed out of the sandbox by its own flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start one server confined and another free. Returns a disabled sandbox rather than an error when the host has no sandbox slice at all, so an absent config and an opted-out feature read alike at the launch site. A host must ask per feature rather than reuse the session config, because reading only `enabled` confines a server the user opted out of, or reports as sandboxed one that is not. + /// The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. + /// The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. + /// The to monitor for cancellation requests. The default is . + /// The sandbox a named feature actually launches under. + internal async Task ResolveForOptionalAsync(string routingFlag, object? sandbox = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(routingFlag); + + var request = new SandboxEffectiveForOptionalParams { RoutingFlag = routingFlag, Sandbox = CopilotClient.ToJsonElementForWire(sandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.resolveForOptional", [request], cancellationToken); + } + + /// Reports whether this machine can run an OS-level command sandbox at all. A host must ask before it offers sandboxing, because the answer is a property of the machine rather than of any setting: on Linux it depends on bubblewrap being installed, and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a process the first time, so the answer is cached for the life of the runtime. A host that assumes support and enables the sandbox anyway produces a session in which every shell command fails. + /// The to monitor for cancellation requests. The default is . + /// True when an OS-level sandbox can run on this host. + internal async Task CheckPlatformSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.checkPlatformSupport", [], cancellationToken); + } + + /// Reports whether this Windows host's BaseContainer implementation can reach the host's loopback interface directly, which is what a local-network policy needs to avoid routing through the egress proxy. Like `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather than of any setting, and resolving it the first time spawns a platform probe. A host that offers the direct local-network option on a machine that lacks the capability produces a session whose sandboxed commands cannot reach local services. Always false off Windows. + /// The to monitor for cancellation requests. The default is . + /// True when the sandbox on this host can reach host loopback directly. + internal async Task CheckWindowsHostLoopbackSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.checkWindowsHostLoopbackSupport", [], cancellationToken); + } + + /// The explanation a host shows when it refuses an explicit request to turn the sandbox on for a machine that cannot run one. Carries the platform-specific remedy — install bubblewrap, update Windows — and the documentation link, so a host that got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason and cannot describe the same machine differently from the runtime's own spawn path. + /// The to monitor for cancellation requests. The default is . + /// The user-facing refusal, including the platform remedy and the documentation link. + internal async Task GetUnsupportedMessageAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getUnsupportedMessage", [], cancellationToken); + } + + /// The notice a host shows when a stored `sandbox` setting is being ignored for this session because the machine cannot enforce it. Distinct from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports that a setting the user already saved is inert, states that commands will run unsandboxed, and confirms the stored setting itself is left alone. A host that stays silent here leaves the user believing a sandbox is active. + /// The to monitor for cancellation requests. The default is . + /// The user-facing notice that a saved sandbox setting is inert for this session. + internal async Task GetUnsupportedSettingDisabledNoticeAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getUnsupportedSettingDisabledNotice", [], cancellationToken); + } + + /// The warning a host prints at startup when a session asked for a sandbox on a machine that cannot run one. The third of the unsupported notices, and the only one that depends on the policy in force: it names the remedy the reader can actually act on, which is the stored setting for an unmanaged host, an administrator for a managed one, and waiting for the policy to resolve when the sandbox stayed on only because the policy could not be determined. Returns no notice when the machine does support a sandbox, so a host can call it unconditionally on the startup path. A host that composes its own warning tells a managed user to change a setting their policy will overwrite. + /// The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. + /// True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. + /// The to monitor for cancellation requests. The default is . + /// The startup warning, absent when the machine can run a sandbox. + internal async Task GetUnsupportedStartupNoticeAsync(object? managedSandbox = null, bool? enabledByUndeterminedPolicy = null, CancellationToken cancellationToken = default) + { + var request = new SandboxUnsupportedStartupNoticeParams { ManagedSandbox = CopilotClient.ToJsonElementForWire(managedSandbox), EnabledByUndeterminedPolicy = enabledByUndeterminedPolicy }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getUnsupportedStartupNotice", [request], cancellationToken); + } + + /// Whether one slash command stays reachable while sandbox enforcement is unavailable and the session is otherwise blocked. The permitted set is deliberately narrow — commands that only report state, and the few that let the user repair or leave the situation — and it is keyed on the arguments as well as the name, so `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than keep its own list: a command this returns false for is one the runtime would refuse anyway, and a divergent list either strands the user with no way out or admits a command that acts on an unenforced session. + /// The command name as the user typed it, with or without its leading slash. + /// The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. + /// The to monitor for cancellation requests. The default is . + /// True when the command stays available while enforcement is blocked. + internal async Task CheckEnforcementCommandAsync(string commandName, IList args, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(commandName); + ArgumentNullException.ThrowIfNull(args); + + var request = new SandboxEnforcementCommandAllowedParams { CommandName = commandName, Args = args }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.checkEnforcementCommand", [request], cancellationToken); + } + + /// Returns the documentation URL a host should point a user at when it declines or downgrades a sandbox setting. The runtime owns the address so every surface cites the same page and a host does not hard-code a link that later moves. + /// The to monitor for cancellation requests. The default is . + /// The documentation URL a host cites when it declines or downgrades a sandbox setting. + internal async Task GetDocsUrlAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getDocsUrl", [], cancellationToken); + } + + /// Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. + /// The to monitor for cancellation requests. The default is . + /// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. + public async Task GetHostSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getHostSupport", [], cancellationToken); + } + + /// ProxyCa APIs. + public ServerSandboxProxyCaApi ProxyCa => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// ProxySecret APIs. + public ServerSandboxProxySecretApi ProxySecret => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Settings APIs. + public ServerSandboxSettingsApi Settings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} + +/// Provides server-scoped SandboxProxyCa APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerSandboxProxyCaApi +{ + private readonly JsonRpc _rpc; + + internal ServerSandboxProxyCaApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Reports whether this runtime process can offer installing the sandbox credential-proxy certificate authority into OS trust. + /// The to monitor for cancellation requests. The default is . + /// True when this process can offer installing the sandbox credential-proxy certificate authority into OS trust. + public async Task CheckInstallationSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.checkInstallationSupport", [], cancellationToken); + } + + /// Reports whether this sandbox configuration uses the credential proxy and can need certificate-authority setup. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// True when the sandbox configuration uses the credential proxy and can need certificate-authority setup. + public async Task CheckRelevanceAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.checkRelevance", [request], cancellationToken); + } + + /// Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task GetStatusAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.getStatus", [request], cancellationToken); + } + + /// Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Result of creating the persistent certificate authority of the sandbox credential proxy. + public async Task CreateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.create", [request], cancellationToken); + } + + /// Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task RotateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.rotate", [request], cancellationToken); + } + + /// Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task TrustAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.trust", [request], cancellationToken); + } + + /// Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task RemoveAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.remove", [], cancellationToken); + } +} + +/// Provides server-scoped SandboxProxySecret APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsErrorCode : IEquatable +public sealed class ServerSandboxProxySecretApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SessionFsErrorCode(string value) + internal ServerSandboxProxySecretApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The requested path does not exist. - public static SessionFsErrorCode ENOENT { get; } = new("ENOENT"); - - /// The filesystem operation failed for an unspecified reason. - public static SessionFsErrorCode UNKNOWN { get; } = new("UNKNOWN"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsErrorCode left, SessionFsErrorCode right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsErrorCode left, SessionFsErrorCode right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is SessionFsErrorCode other && Equals(other); + /// Reports where this runtime keeps the sandbox proxy password: the credential store directory and the entry identifier within it. Both are derived from the configuration directory this runtime was started with, so a host does not resolve them itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this runtime's own proxy password rather than a reference the user wrote by hand. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The to monitor for cancellation requests. The default is . + /// Where this runtime keeps the sandbox proxy password. + internal async Task GetLocationAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.getLocation", [], cancellationToken); + } - /// - public bool Equals(SessionFsErrorCode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Reads the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to the on-disk store. Reports an absent value rather than failing when no entry exists. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The to monitor for cancellation requests. The default is . + /// The stored sandbox proxy password, if one is present. + internal async Task GetAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.get", [], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Stores the sandbox proxy password in the credential store `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether the OS keychain accepted it or it fell back to the on-disk store. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The password to store for the sandbox proxy. + /// The to monitor for cancellation requests. The default is . + /// Where the sandbox proxy password was stored. + internal async Task SaveAsync(string value, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(value); - /// - public override string ToString() => Value; + var request = new SandboxProxySecretSaveRequest { Value = value }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.save", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Removes the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to call while clearing a proxy password whose origin is unknown. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The to monitor for cancellation requests. The default is . + internal async Task DeleteAsync(CancellationToken cancellationToken = default) { - /// - public override SessionFsErrorCode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, SessionFsErrorCode value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsErrorCode)); - } + await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.delete", [], cancellationToken); } } - -/// Entry type. +/// Provides server-scoped SandboxSettings APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsReaddirWithTypesEntryType : IEquatable +public sealed class ServerSandboxSettingsApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SessionFsReaddirWithTypesEntryType(string value) + internal ServerSandboxSettingsApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The entry is a file. - public static SessionFsReaddirWithTypesEntryType File { get; } = new("file"); - - /// The entry is a directory. - public static SessionFsReaddirWithTypesEntryType Directory { get; } = new("directory"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is SessionFsReaddirWithTypesEntryType other && Equals(other); - - /// - public bool Equals(SessionFsReaddirWithTypesEntryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Resolves a stored sandbox settings object into the effective one, filling every value the user left unset with its default. Read this to render or reason about the sandbox configuration a session would actually run under, rather than the sparse document the user wrote. + /// The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. + /// The to monitor for cancellation requests. The default is . + /// The effective sandbox settings, with every unset value resolved to its default. + internal async Task> ApplyDefaultsAsync(object? stored, CancellationToken cancellationToken = default) + { + var request = new SandboxApplyDefaultsRequest { Stored = CopilotClient.ToJsonElementForWire(stored) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "sandbox.settings.applyDefaults", [request], cancellationToken); + } +} - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); +/// Provides server-scoped Persistence APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerPersistenceApi +{ + private readonly JsonRpc _rpc; - /// - public override string ToString() => Value; + internal ServerPersistenceApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Atomically replaces a JSON file's entire contents while holding the runtime's per-path lock. The lock lives in the runtime process, so a host that writes these files itself takes no part in it and can tear a concurrent runtime write; route the write here instead. Unlike a merging write this never reads or parses the existing file, so a previously corrupted snapshot is replaced wholesale rather than failing every later write. Use it only for callers that always persist a complete snapshot. + /// Absolute path of the file to replace. Parent directories are created when missing. + /// The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. + /// Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. + /// The to monitor for cancellation requests. The default is . + /// The outcome of a locked snapshot write. + internal async Task WriteRawJsonLockedAsync(string path, string dataJson, string? fileHeader = null, CancellationToken cancellationToken = default) { - /// - public override SessionFsReaddirWithTypesEntryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + ArgumentNullException.ThrowIfNull(path); + ArgumentNullException.ThrowIfNull(dataJson); - /// - public override void Write(Utf8JsonWriter writer, SessionFsReaddirWithTypesEntryType value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsReaddirWithTypesEntryType)); - } + var request = new PersistenceWriteRawJsonLockedRequest { Path = path, DataJson = dataJson, FileHeader = fileHeader }; + return await CopilotClient.InvokeRpcAsync(_rpc, "persistence.writeRawJsonLocked", [request], cancellationToken); } } - -/// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected). +/// Provides server-scoped User APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsSqliteQueryType : IEquatable +public sealed class ServerUserApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SessionFsSqliteQueryType(string value) + internal ServerUserApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Settings APIs. + public ServerUserSettingsApi Settings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} - /// Execute DDL or multi-statement SQL without returning rows. - public static SessionFsSqliteQueryType Exec { get; } = new("exec"); +/// Provides server-scoped UserSettings APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerUserSettingsApi +{ + private readonly JsonRpc _rpc; - /// Execute a SELECT-style query and return rows. - public static SessionFsSqliteQueryType Query { get; } = new("query"); + internal ServerUserSettingsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Execute INSERT, UPDATE, or DELETE SQL and return affected-row metadata. - public static SessionFsSqliteQueryType Run { get; } = new("run"); + /// Adds or removes one hook key in the user `disabledHooks` setting, rewriting settings.json in place and leaving every other setting untouched. Reports a typed outcome rather than failing the call, so a host can tell an unparseable settings file apart from a write that could not complete. + /// Path of the settings.json to rewrite. + /// Durable content-hash key of the hook, as `hooks.loadResources` reports it. + /// True adds the key to `disabledHooks`, false removes it. + /// The to monitor for cancellation requests. The default is . + /// Outcome of rewriting the `disabledHooks` setting. + internal async Task SetHookDisabledAsync(string settingsPath, string disableKey, bool disabled, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(settingsPath); + ArgumentNullException.ThrowIfNull(disableKey); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => left.Equals(right); + var request = new UserSettingsSetHookDisabledRequest { SettingsPath = settingsPath, DisableKey = disableKey, Disabled = disabled }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.setHookDisabled", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => !(left == right); + /// Reads the user's settings document exactly as `user.settings.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the settings read match the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `user.settings.load`. Hook-validation relaxations are deliberately not caller-supplied: they continue to come from the server's environment, so a consumer cannot widen the host's hook policy through this method. + /// Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. + /// The to monitor for cancellation requests. The default is . + /// The stored user settings document, keyed by setting name. + internal async Task> LoadForConfigDirAsync(string? configDir = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsLoadForConfigDirRequest { ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "user.settings.loadForConfigDir", [request], cancellationToken); + } - /// - public override bool Equals(object? obj) => obj is SessionFsSqliteQueryType other && Equals(other); + /// Reads a repository's checked-in settings document as stored, normalized, together with any diagnostic raised while reading it. This is the repository half of the layering `user.settings.get` reports: `user.settings.load` reads the user's own document, and this reads the one a repository checks in to govern the keys `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, or that sets a key a repository may not govern, is reported through `warning` while the settings that did load are still returned, so a consumer surfaces the diagnostic and continues rather than failing the session. When `repoRoot` is the user's home directory the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as repository policy. + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + /// The to monitor for cancellation requests. The default is . + /// A repository's settings as stored, together with any diagnostic raised while reading them. + internal async Task LoadRepoAsync(string repoRoot, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); - /// - public bool Equals(SessionFsSqliteQueryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + var request = new UserSettingsLoadRepoRequest { RepoRoot = repoRoot }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadRepo", [request], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Reads a repository's settings and merges them over a supplied user layer in one step, returning the settings a consumer should act on inside that repository. Use this rather than reading the two layers separately: the merge is per setting and collection-aware, so a repository adds to the collections it is allowed to influence without replacing the user's own entries, and a whole-document overlay would get that wrong. Any diagnostic raised while reading the repository layer is returned rather than printed, so the consumer decides how to surface it; the settings that did load are merged regardless. + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + /// The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. + /// The to monitor for cancellation requests. The default is . + /// The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. + internal async Task LoadAndMergeRepoAsync(string repoRoot, IDictionary userSettings, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(userSettings); - /// - public override string ToString() => Value; + var request = new UserSettingsLoadAndMergeRepoRequest { RepoRoot = repoRoot, UserSettings = userSettings }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadAndMergeRepo", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Reports the on-disk path of the settings document `user.settings.load` and `user.settings.set` read and write. Resolved the same way those methods resolve it, so a host that shows or opens the settings file names the file the runtime actually uses, including the extensionless legacy `settings` file when that is what is present. + /// The to monitor for cancellation requests. The default is . + /// The on-disk location of the user's settings document. + internal async Task GetPathAsync(CancellationToken cancellationToken = default) { - /// - public override SessionFsSqliteQueryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, SessionFsSqliteQueryType value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteQueryType)); - } + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getPath", [], cancellationToken); } -} + /// Reads the user's stored settings together with the diagnostic raised while reading them. This is `user.settings.load` plus the reason part of the document was ignored: that one answers the document alone, so a caller cannot tell a clean read from a salvaged one. Read this when the caller is about to write the file back, where accepting a partial parse would discard every value the loader could not read. The settings that did load are still reported alongside the warning, so a consumer may surface it and continue instead of failing. + /// The to monitor for cancellation requests. The default is . + /// The user's stored settings, together with any diagnostic raised while reading them. + internal async Task LoadWithWarningAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadWithWarning", [], cancellationToken); + } -/// SQLite transaction failure classification. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsSqliteTransactionErrorClass : IEquatable -{ - private readonly string? _value; + /// Folds a user settings layer over a managed (enterprise policy) layer and returns the merged settings. The managed layer's governance keys win, `autoTier` resolves through its overridable form, and the two per-entry control maps (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped back from the managed layer, so each entry an administrator declares wins while the user keeps control of the rest. The parameters are named for their layers rather than being a generic base/override pair: nothing about a settings object identifies which layer produced it, so the runtime cannot detect a transposed call, and transposing one resolves the governance keys in the user's favour instead of the administrator's. Supplying only one layer returns it unchanged, and supplying neither returns an empty object. Rejects a managed `autoTier` that is neither a user-configurable tier nor a single-key overridable form, rather than silently dropping it. + /// The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. + /// The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. + /// The to monitor for cancellation requests. The default is . + /// The user layer folded over the managed layer. + internal async Task MergeManagedAndUserAsync(object? managed = null, object? user = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsMergeManagedAndUserParams { Managed = CopilotClient.ToJsonElementForWire(managed), User = CopilotClient.ToJsonElementForWire(user) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.mergeManagedAndUser", [request], cancellationToken); + } - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SessionFsSqliteTransactionErrorClass(string value) + /// Folds a repository's settings layer into the user layer. Each repo-overridable key carries a directional policy chosen so a repository can only add restrictions and never relax the user's own. The two per-entry managed control maps are the exception those directional rules cannot express — a repository may legitimately enable plugins and declare marketplaces — so they are re-stamped afterwards from the runtime's ambient managed policy. That makes the result depend on the runtime process's managed state and not on the arguments alone: a host must call this rather than reimplement the fold, or a repository could relax a restriction the administrator imposed. Rejects when either layer is not a JSON object. + /// The user's settings, already resolved against any managed layer. + /// The repository's checked-in settings layer. + /// The to monitor for cancellation requests. The default is . + /// The repository layer folded into the user layer. + internal async Task MergeRepoValueAsync(object? userSettings, object? repoSettings, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + var request = new UserSettingsMergeRepoValueParams { UserSettings = CopilotClient.ToJsonElementForWire(userSettings) ?? JsonElement.Parse("null"), RepoSettings = CopilotClient.ToJsonElementForWire(repoSettings) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.mergeRepoValue", [request], cancellationToken); } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Runs the one-time migration that moves a staff account's update channel to stable, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file, re-reads the completion stamp inside it, and returns `current` rather than migrating twice, so two hosts racing at startup cannot both migrate. Only a `migrated` status means the persisted settings changed and the caller should reload them. An account on the experimental channel is deliberately left alone and reported as `excluded-experimental`. + /// The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. + /// The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. + /// The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time staff update-channel migration. + internal async Task MigrateStaffUpdateChannelOnceAsync(string homeDirectory, IDictionary environment, string? configDir = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(homeDirectory); + ArgumentNullException.ThrowIfNull(environment); - /// SQLite reported BUSY or LOCKED before commit; the transaction was rolled back and may be retried. - public static SessionFsSqliteTransactionErrorClass BusyOrLocked { get; } = new("busyOrLocked"); + var request = new UserSettingsHostContext { HomeDirectory = homeDirectory, Environment = environment, ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.migrateStaffUpdateChannelOnce", [request], cancellationToken); + } - /// The statement, database, or provider failed definitively and must not be retried automatically. - public static SessionFsSqliteTransactionErrorClass Fatal { get; } = new("fatal"); + /// Runs the one-time reset that clears a staff account's pinned model selection, and reports the timestamp the host should record. Idempotent and self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the timestamp it recorded gets `didReset: false` rather than a second reset. It applies to staff accounts only; any other account is reported as not reset without the settings document being opened. Only `didReset: true` means the persisted settings changed, and only then are the updated settings returned for the host to adopt. + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the reset is evaluated against the server's own home instead. + /// Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. + /// When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time staff model-selection reset. + internal async Task ResetStaffModelSelectionOnceAsync(UserSettingsHostContext context, bool? staff = null, string? staffModelResetAt = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); - /// The transport failed after the provider may have committed; retrying could duplicate effects. - public static SessionFsSqliteTransactionErrorClass PostCommitAmbiguous { get; } = new("postCommitAmbiguous"); + var request = new UserSettingsResetStaffModelSelectionOnceRequest { Context = context, Staff = staff, StaffModelResetAt = staffModelResetAt }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.resetStaffModelSelectionOnce", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => left.Equals(right); + /// Reports the top-level keys in the user settings document that the runtime does not recognize, phrased for display to the user. This is a separate question from the warning `user.settings.loadWithWarning` returns: that one describes parts of the document the loader had to ignore to load the rest, whereas an unknown key parses cleanly and is simply not a setting, so a host that surfaces only the load warning silently accepts a misspelled key that will never take effect. Nothing is reported when the document is absent, unreadable, or failed to load, because an unknown-key list derived from a document the runtime could not read would be misleading rather than helpful. Inspection never modifies the document. + /// The configuration directory, home directory and environment to resolve the settings document from. A host that scopes a session to its own Copilot home must pass that directory here, or the server's own home is inspected instead. + /// The to monitor for cancellation requests. The default is . + /// The unrecognized top-level keys found in the user settings document, already phrased for display. + internal async Task GetUnknownKeysWarningAsync(UserSettingsHostContext context, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => !(left == right); + var request = new UserSettingsUnknownKeysWarningRequest { Context = context }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getUnknownKeysWarning", [request], cancellationToken); + } - /// - public override bool Equals(object? obj) => obj is SessionFsSqliteTransactionErrorClass other && Equals(other); + /// Resolves the effective runtime settings for a host that is about to start a session, layering the given overrides over the settings documents, the environment and the platform defaults. A host cannot assemble this itself: the precedence between a user document, a repository document, the managed layers and the environment is the runtime's own rule, and a host that re-implements it drifts from the server it is configuring. The working directory, environment and platform are taken as arguments rather than read from the server process, so a host resolving settings for a directory other than its own gets that directory's answer. Nothing is written; this only computes. + /// The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. + /// The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. + /// The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. + /// Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. + /// The to monitor for cancellation requests. The default is . + /// The effective runtime settings, keyed by setting name. Keys this runtime does not recognize are preserved rather than dropped, so a caller reading a document written by a newer runtime keeps every value. + internal async Task> BuildRuntimeAsync(string workingDirectory, IDictionary environment, string platform, IDictionary? overrides = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(workingDirectory); + ArgumentNullException.ThrowIfNull(environment); + ArgumentNullException.ThrowIfNull(platform); - /// - public bool Equals(SessionFsSqliteTransactionErrorClass other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + var request = new UserSettingsBuildRuntimeRequest { WorkingDirectory = workingDirectory, Environment = environment, Platform = platform, Overrides = overrides }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "user.settings.buildRuntime", [request], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Runs the one-time migration that moves a staff account's log level to the current default, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file and re-reads the completion stamp inside it, so two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the persisted settings, and the settings it returns are the document re-read after the write, so a host should adopt them rather than reloading separately and racing the next writer. + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the migration is evaluated against the server's own home instead. + /// When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time staff log-level migration. + internal async Task MigrateStaffLogLevelOnceAsync(UserSettingsHostContext context, string? cachedCompletedAt = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); - /// - public override string ToString() => Value; + var request = new UserSettingsMigrateStaffLogLevelOnceRequest { Context = context, CachedCompletedAt = cachedCompletedAt }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.migrateStaffLogLevelOnce", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Runs the one-time cleanup that removes obsolete CLI-owned settings and legacy rubber-duck keys from the user's settings document, and reports what it did. Idempotent and safe to call on every startup: with nothing obsolete left it reports `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so a setting written by a newer host is never dropped by an older one, and a document that fails to parse is reported `invalid` and left untouched rather than rewritten from a partial read. The cleaned document is not returned: it is written before this replies, so `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys through `user.settings.unknownKeys` wants this first, because the keys this retires would otherwise be shown to the user as if they were misspelled settings. + /// The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time obsolete-settings cleanup. + internal async Task MigrateObsoleteOnDiskAsync(string? configDir = null, CancellationToken cancellationToken = default) { - /// - public override SessionFsSqliteTransactionErrorClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, SessionFsSqliteTransactionErrorClass value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteTransactionErrorClass)); - } + var request = new UserSettingsMigrateObsoleteOnDiskRequest { ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.migrateObsoleteOnDisk", [request], cancellationToken); } -} + /// Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. + /// The to monitor for cancellation requests. The default is . + /// Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. + public async Task GetAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.get", [], cancellationToken); + } -/// Defines the allowed values. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct HostExitReason : IEquatable -{ - private readonly string? _value; + /// Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + /// The to monitor for cancellation requests. The default is . + /// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + internal async Task GetPathsAsync(string? repoRoot = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsGetPathsRequest { RepoRoot = repoRoot }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getPaths", [request], cancellationToken); + } - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public HostExitReason(string value) + /// Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. + /// Partial user settings to write, as a free-form object keyed by setting name. + /// The to monitor for cancellation requests. The default is . + public async Task SetAsync(object? settings, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + var request = new UserSettingsSetRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.set", [request], cancellationToken); } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + /// The to monitor for cancellation requests. The default is . + /// Top-level user-setting keys grouped by who may govern them. + internal async Task ListGovernanceKeysAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.listGovernanceKeys", [], cancellationToken); + } - /// The owner requested disposal. - public static HostExitReason Disposed { get; } = new("disposed"); + /// Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + /// The to monitor for cancellation requests. The default is . + /// Outcome of an atomic user or repository settings edit. + internal async Task EditAsync(IList canonicalPath, SettingsEditOperation operation, string? configDir = null, object? value = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(canonicalPath); - /// The hosting task or its SDK transport exited; this does not mean the runtime process exited. - public static HostExitReason Exited { get; } = new("exited"); + var request = new UserSettingsEditRequest { CanonicalPath = canonicalPath, Operation = operation, ConfigDir = configDir, Value = CopilotClient.ToJsonElementForWire(value) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.edit", [request], cancellationToken); + } - /// The owning SDK connection disconnected. - public static HostExitReason OwnerDisconnected { get; } = new("ownerDisconnected"); + /// Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + /// Free-form settings object, possibly using legacy or snake_case key names. + /// The to monitor for cancellation requests. The default is . + /// Settings object with canonical key names. + internal async Task NormalizeAsync(object? settings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsNormalizeRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.normalize", [request], cancellationToken); + } - /// The runtime is shutting down. - public static HostExitReason RuntimeShutdown { get; } = new("runtimeShutdown"); + /// Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + /// Layers to diagnose, in the precedence order the caller applies them. + /// The to monitor for cancellation requests. The default is . + /// The settings that will not take effect across the given layers. + internal async Task DiagnoseProblemsAsync(IList? sources = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsProblemsRequest { Sources = sources }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.diagnoseProblems", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(HostExitReason left, HostExitReason right) => left.Equals(right); + /// Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + /// Canonical path of the setting the caller is editing. Currently informational only. + /// Top-level setting name to write. + /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + /// True to remove the top-level key instead of writing it. + /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + /// The to monitor for cancellation requests. The default is . + /// Outcome of validating and writing one top-level setting subtree. + internal async Task ApplyTopKeyAsync(IList canonicalPath, string topKey, object? value = null, bool? delete = null, bool? completeStaffUpdateChannelMigration = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(canonicalPath); + ArgumentNullException.ThrowIfNull(topKey); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(HostExitReason left, HostExitReason right) => !(left == right); + var request = new UserSettingsApplyTopKeyRequest { CanonicalPath = canonicalPath, TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete, CompleteStaffUpdateChannelMigration = completeStaffUpdateChannelMigration }; + var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.UserSettingsApplyTopKeyRequest)!.AsObject(); + if (request.Delete != true && request.Value is null) payload["value"] = null; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.applyTopKey", [payload], cancellationToken); + } - /// - public override bool Equals(object? obj) => obj is HostExitReason other && Equals(other); + /// Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteAllAsync(object? settings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsWriteAllRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.writeAll", [request], cancellationToken); + } - /// - public bool Equals(HostExitReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + /// Top-level user-setting key to merge into, such as `extensions`. + /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + /// The to monitor for cancellation requests. The default is . + /// The stored value of the user setting after the merge. + internal async Task UpdateAsync(string key, object? value, string? configDir = null, string? subDir = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + var request = new UserSettingsUpdateRequest { Key = key, Value = CopilotClient.ToJsonElementForWire(value) ?? JsonElement.Parse("null"), ConfigDir = configDir, SubDir = subDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.update", [request], cancellationToken); + } - /// - public override string ToString() => Value; + /// Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + /// The to monitor for cancellation requests. The default is . + /// Contents of settings.json as stored, for a caller about to rewrite it. + internal async Task LoadForEditAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadForEdit", [], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. + /// Top-level setting name to validate. + /// Value to validate. Omitted when `delete` is true. + /// True to validate a removal of this key. The current settings file is not read. + /// The to monitor for cancellation requests. The default is . + /// Outcome of validating one top-level setting subtree. + internal async Task ValidateAsync(string topKey, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) { - /// - public override HostExitReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + ArgumentNullException.ThrowIfNull(topKey); - /// - public override void Write(Utf8JsonWriter writer, HostExitReason value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HostExitReason)); - } + var request = new UserSettingsValidateRequest { TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.validate", [request], cancellationToken); } } - -/// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. +/// Provides server-scoped Repo APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct LlmInferenceHttpRequestStartTransport : IEquatable +public sealed class ServerRepoApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public LlmInferenceHttpRequestStartTransport(string value) + internal ServerRepoApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Settings APIs. + public ServerRepoSettingsApi Settings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} - /// Plain HTTP or SSE response. Each body chunk is an opaque byte range; the response is a status line, headers, and a (possibly streamed) body. - public static LlmInferenceHttpRequestStartTransport Http { get; } = new("http"); +/// Provides server-scoped RepoSettings APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerRepoSettingsApi +{ + private readonly JsonRpc _rpc; - /// Full-duplex WebSocket channel. Each body chunk maps to exactly one WebSocket message and the `binary` flag distinguishes text from binary frames; request and response chunks flow concurrently. - public static LlmInferenceHttpRequestStartTransport Websocket { get; } = new("websocket"); + internal ServerRepoSettingsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => left.Equals(right); + /// Atomically edits one allowed top-level repository setting. Reads the raw file, preserves unrelated keys, applies one scalar or list edit, validates the result and writes under one file lock, so concurrent sibling or list edits are not lost. A malformed or unsafe existing file returns `invalid` without a write; rejected keys, invalid values and I/O errors reject the call. + /// Absolute path of the repository root. + /// Shared or local repository settings file. + /// One canonical top-level repository setting that the allowlist permits. + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + /// The to monitor for cancellation requests. The default is . + /// Outcome of an atomic user or repository settings edit. + internal async Task EditAsync(string repoRoot, RepoSettingsEditScope scope, string key, SettingsEditOperation operation, object? value = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(key); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => !(left == right); + var request = new RepoSettingsEditRequest { RepoRoot = repoRoot, Scope = scope, Key = key, Operation = operation, Value = CopilotClient.ToJsonElementForWire(value) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.edit", [request], cancellationToken); + } - /// - public override bool Equals(object? obj) => obj is LlmInferenceHttpRequestStartTransport other && Equals(other); + /// Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// The to monitor for cancellation requests. The default is . + /// Parsed repository settings without normalization or layering. + internal async Task ReadRawAsync(string repoRoot, string scope, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); - /// - public bool Equals(LlmInferenceHttpRequestStartTransport other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + var request = new RepoSettingsReadRawRequest { RepoRoot = repoRoot, Scope = scope }; + return await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.readRaw", [request], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// Canonical top-level key permitted by the repository settings allowlist. + /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + /// True to remove the key instead of writing it. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteKeyAsync(string repoRoot, string scope, string key, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); + ArgumentNullException.ThrowIfNull(key); - /// - public override string ToString() => Value; + var request = new RepoSettingsWriteKeyRequest { RepoRoot = repoRoot, Scope = scope, Key = key, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; + var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.RepoSettingsWriteKeyRequest)!.AsObject(); + if (request.Delete != true && request.Value is null) payload["value"] = null; + await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeKey", [payload], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteAllAsync(string repoRoot, string scope, object? settings, CancellationToken cancellationToken = default) { - /// - public override LlmInferenceHttpRequestStartTransport Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); - /// - public override void Write(Utf8JsonWriter writer, LlmInferenceHttpRequestStartTransport value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(LlmInferenceHttpRequestStartTransport)); - } + var request = new RepoSettingsWriteAllRequest { RepoRoot = repoRoot, Scope = scope, Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeAll", [request], cancellationToken); } } - -/// Why the runtime is requesting a GitHub credential. +/// Provides server-scoped FeatureFlags APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct GitHubTokenAcquireReason : IEquatable +public sealed class ServerFeatureFlagsApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public GitHubTokenAcquireReason(string value) + internal ServerFeatureFlagsApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The runtime is acquiring the registration's first credential. - public static GitHubTokenAcquireReason Initial { get; } = new("initial"); - - /// The runtime is replacing a credential that is approaching expiry. - public static GitHubTokenAcquireReason Refresh { get; } = new("refresh"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is GitHubTokenAcquireReason other && Equals(other); - - /// - public bool Equals(GitHubTokenAcquireReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Resolves named gates against this installation's cached online-experiment assignment, for the account the runtime is already authenticated as. Unlike `featureFlags.resolve`, which layers static availability with the populations supplied, this reads the experiment assignment the runtime cached for its own current authentication, so a launch can honor a rollout before any session exists. The account is never taken from the request: naming one would read another account's cached assignments. The cached assignment answers immediately and any network refresh happens behind it, so this call does not wait on the network. Not available to an extension, which cannot carry the user's consent to read their assignment. + /// The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. + /// Whether the caller is GitHub or Microsoft staff. + /// Whether the caller is in an experimental population. + /// Whether the caller belongs to a team plan. + /// Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. + /// Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + /// Environment to read flag overrides from. Defaults to this runtime process's own environment. + /// User settings document whose `featureFlags` block is layered on top of the resolved set. + /// When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. + /// The to monitor for cancellation requests. The default is . + /// The resolved gates, keyed by flag name. + internal async Task> ResolveStartupGatesAsync(IList flags, bool isStaff, bool isExperimental, bool isTeam, bool streamerMode, bool refreshWithoutSession, bool? isStaffGithub = null, bool? isStaffMicrosoft = null, IDictionary? environment = null, object? config = null, double? firstLaunchAtMillis = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(flags); - /// - public override string ToString() => Value; + var request = new FeatureFlagsResolveStartupGatesRequest { Flags = flags, IsStaff = isStaff, IsExperimental = isExperimental, IsTeam = isTeam, StreamerMode = streamerMode, RefreshWithoutSession = refreshWithoutSession, IsStaffGitHub = isStaffGithub, IsStaffMicrosoft = isStaffMicrosoft, Environment = environment, Config = CopilotClient.ToJsonElementForWire(config), FirstLaunchAtMillis = firstLaunchAtMillis }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "featureFlags.resolveStartupGates", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. + /// The to monitor for cancellation requests. The default is . + /// Every feature flag this runtime declares, with the shape each one was declared with. + internal async Task ListMetadataAsync(CancellationToken cancellationToken = default) { - /// - public override GitHubTokenAcquireReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + return await CopilotClient.InvokeRpcAsync(_rpc, "featureFlags.listMetadata", [], cancellationToken); + } - /// - public override void Write(Utf8JsonWriter writer, GitHubTokenAcquireReason value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(GitHubTokenAcquireReason)); - } + /// Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. + /// Whether the caller is GitHub or Microsoft staff. + /// Whether the caller is in an experimental population. + /// Whether the caller belongs to the team population used by feature availability. + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + /// Flags forced to a value after every other layer, keyed by flag name. + /// The to monitor for cancellation requests. The default is . + /// The resolved feature flags, keyed by flag name. + internal async Task> ResolveAsync(bool isStaff, bool isExperimental, bool isTeam, bool? isStaffGithub = null, bool? isStaffMicrosoft = null, IDictionary? baseFlags = null, IDictionary? environment = null, object? config = null, IDictionary? flagOverrides = null, CancellationToken cancellationToken = default) + { + var request = new FeatureFlagsResolveRequest { IsStaff = isStaff, IsExperimental = isExperimental, IsTeam = isTeam, IsStaffGitHub = isStaffGithub, IsStaffMicrosoft = isStaffMicrosoft, BaseFlags = baseFlags, Environment = environment, Config = CopilotClient.ToJsonElementForWire(config), FlagOverrides = flagOverrides }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "featureFlags.resolve", [request], cancellationToken); } } - -/// Explicit user decisions, never inferred from a permission grant or model response. +/// Provides server-scoped Permissions APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct InstallationDecision : IEquatable +public sealed class ServerPermissionsApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public InstallationDecision(string value) + internal ServerPermissionsApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The user explicitly approved the exact review on this request. - public static InstallationDecision Confirm { get; } = new("confirm"); - - /// The user declined the reviewed operation. - public static InstallationDecision Decline { get; } = new("decline"); + /// Interprets a verbatim managed `permissions` slice into the three policy questions a host asks before granting elevated permissions: whether bypass-permissions mode is forbidden, whether a policy exists that this build could not determine, and whether the layer supplies permission rules the session must enforce. An absent or empty slice means no managed policy applies. The runtime and its permission service share one policy type, so a new managed permission setting is interpreted in exactly one place; a host that reimplements the reading would silently diverge the first time that set grows. Hosts must fail closed on an undetermined policy rather than treating it as permission granted. + /// The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. + /// The to monitor for cancellation requests. The default is . + /// The policy questions a host asks before granting elevated permissions. + internal async Task EvaluateManagedPolicyAsync(object? permissions = null, CancellationToken cancellationToken = default) + { + var request = new PermissionsEvaluateManagedPolicyParams { Permissions = CopilotClient.ToJsonElementForWire(permissions) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "permissions.evaluateManagedPolicy", [request], cancellationToken); + } - /// The user cancelled the pending decision without granting consent. - public static InstallationDecision Cancel { get; } = new("cancel"); + /// Locations APIs. + public ServerPermissionsLocationsApi Locations => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstallationDecision left, InstallationDecision right) => left.Equals(right); + /// FolderTrust APIs. + public ServerPermissionsFolderTrustApi FolderTrust => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstallationDecision left, InstallationDecision right) => !(left == right); +/// Provides server-scoped PermissionsLocations APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerPermissionsLocationsApi +{ + private readonly JsonRpc _rpc; - /// - public override bool Equals(object? obj) => obj is InstallationDecision other && Equals(other); + internal ServerPermissionsLocationsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// - public bool Equals(InstallationDecision other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Drops stored per-location permission grants whose directory no longer exists, and reports which location keys were removed. Runs against the permission store under the runtime's own Copilot home, the same store `session.permissions.locations.resolve` reads. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to prune its own permission store. + /// The to monitor for cancellation requests. The default is . + /// Which stored location permissions were dropped because their directory is gone. + internal async Task CleanupOrphanedAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "permissions.locations.cleanupOrphaned", [], cancellationToken); + } +} - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); +/// Provides server-scoped PermissionsFolderTrust APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerPermissionsFolderTrustApi +{ + private readonly JsonRpc _rpc; - /// - public override string ToString() => Value; + internal ServerPermissionsFolderTrustApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Reports whether a folder is trusted, reading the persisted trusted-folders list directly rather than through a session. Use this from a host that has no session yet, such as a one-shot command deciding whether to honor a checkout's own settings. It differs from the session-scoped check in two ways that matter: it takes the configuration directory to read the list from, instead of inheriting the session's, and it answers only from the persisted list, so trust a user granted for the lifetime of one session is not visible here. A host that has a session should prefer the session-scoped check, which also covers session-only trust. + /// Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. + /// Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. + /// The to monitor for cancellation requests. The default is . + /// Folder trust check result. + internal async Task CheckTrustAsync(string path, string? configDir = null, CancellationToken cancellationToken = default) { - /// - public override InstallationDecision Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + ArgumentNullException.ThrowIfNull(path); - /// - public override void Write(Utf8JsonWriter writer, InstallationDecision value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstallationDecision)); - } + var request = new FolderTrustIsTrustedParams { Path = path, ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "permissions.folderTrust.checkTrust", [request], cancellationToken); } } - -/// Provides server-scoped RPC methods (no session required). -public sealed class ServerRpc +/// Provides server-scoped ManagedSettings APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerManagedSettingsApi { private readonly JsonRpc _rpc; - internal ServerRpc(JsonRpc rpc) + internal ServerManagedSettingsApi(JsonRpc rpc) { _rpc = rpc; } - /// Checks server responsiveness and returns protocol information. - /// Optional message to echo back. + /// Discovers device-managed settings the way the runtime's own device layer does, and reports the sandbox floor and the load outcome alongside the validated document. This differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a document that validates to an empty object is reported as absent rather than as an empty policy, a discovery error does not suppress a document that still validates, and a failure is reported as a flag rather than only as error text. Hosts that compose the device layer into an effective policy use this, because `managedSettings.read` cannot distinguish "no device policy" from "device policy could not be read" and would silently hand the user's own layer the win. /// The to monitor for cancellation requests. The default is . - /// Server liveness response, including the echoed message, current server timestamp, and protocol version. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - public async Task PingAsync(string? message = null, CancellationToken cancellationToken = default) + /// The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. + internal async Task ReadDeviceAsync(CancellationToken cancellationToken = default) { - var request = new PingRequest { Message = message }; - return await CopilotClient.InvokeRpcAsync(_rpc, "ping", [request], cancellationToken); + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.readDevice", [], cancellationToken); } - /// Performs the SDK server connection handshake and validates the optional connection token. Marked internal because this is JSON-RPC transport plumbing invoked automatically by an SDK client's own `connect()` wrapper, not a user-facing method. Stays internal as long as the SDK client owns the handshake; would only become public if the SDK ever exposed the raw schema surface to consumers without a connection wrapper. - /// Opt this connection in to GitHub telemetry forwarding for its lifetime. When set, the runtime forwards this host's telemetry across all its sessions, its sessionless events, and explicitly process-wide events over the `gitHubTelemetry.event` notification. Connections intentionally sharing one server receive that server's events; independently embedded runtime hosts do not receive each other's host-owned events. Regular events are also written to the runtime's normal GitHub/CTS path (dual-write); host-only compatibility events are forward-only and intentionally skip that path. Intended for first-party hosts that re-emit the events into their own telemetry stores. Both unrestricted and restricted events are forwarded, each tagged with a `restricted` discriminator; a backstop drops restricted events when restricted telemetry is disabled — using the process-global gate for ordinary events and an explicit session-scoped decision for host-only events. - /// Identity of the integrating host. Optional; omit it to keep the default attribution. - /// Task kinds this connection can decode when observing session tasks. Omit to retain agent and shell compatibility. - /// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN. + /// Retains the supplied managed layers as this runtime process's startup policy and re-applies the result to every live session. Hosts that own their own short-lived process policy use this, so a guarded mutation is checked against the policy the host actually fetched. Retaining is a whole-process replacement rather than a merge, so a host that already resolved a good policy must not retain a partial one over it. The failure flags are honest inputs rather than assumptions: reporting a fetch or load that failed keeps the layers already retained, and the interim fail-closed state, instead of clearing them. + /// Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. + /// Whether any managed policy source exists, independently of fetch failures. + /// Whether the server policy source exists, even when its response is unavailable. + /// Whether a required fresh server-policy confirmation failed. + /// Preserve the retained server layer during a device-only resolution. + /// Whether the device sandbox intent is unreadable independently of its other settings. + /// Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. + /// Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. + /// Whether uncertainty alone enabled the shared sandbox floor. + /// Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. + /// Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. + /// The resolved server policy. A known source can lack a response after a forced-refresh failure. + /// The device/MDM policy layer. + /// Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. + /// Shared server/device sandbox floor, excluding session-local helper policy. + /// The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. /// The to monitor for cancellation requests. The default is . - /// Handshake result reporting the server's protocol version and package version on success. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - internal async Task ConnectAsync(bool? enableGitHubTelemetryForwarding = null, ConnectClientInfo? clientInfo = null, IList? supportedTaskKinds = null, string? token = null, CancellationToken cancellationToken = default) + internal async Task RetainPolicyAsync(bool deviceSourceFound, bool managedPolicyPresent, bool serverSourceFound, bool serverForcedRefreshFailure, bool preserveServerState, bool deviceSandboxUndetermined, bool sandboxFloorUndetermined, bool permissionPolicyUndetermined, bool sandboxEnabledByUndeterminedPolicy, bool serverFetchFailed, bool deviceLoadFailed, object? serverResponse = null, object? deviceResponse = null, object? deviceSandboxFloor = null, object? sharedSandboxFloor = null, object? policyHelperResponse = null, CancellationToken cancellationToken = default) { - var request = new ConnectRequest { EnableGitHubTelemetryForwarding = enableGitHubTelemetryForwarding, ClientInfo = clientInfo, SupportedTaskKinds = supportedTaskKinds, Token = token }; - return await CopilotClient.InvokeRpcAsync(_rpc, "connect", [request], cancellationToken); + var request = new ManagedSettingsRetainPolicyParams { DeviceSourceFound = deviceSourceFound, ManagedPolicyPresent = managedPolicyPresent, ServerSourceFound = serverSourceFound, ServerForcedRefreshFailure = serverForcedRefreshFailure, PreserveServerState = preserveServerState, DeviceSandboxUndetermined = deviceSandboxUndetermined, SandboxFloorUndetermined = sandboxFloorUndetermined, PermissionPolicyUndetermined = permissionPolicyUndetermined, SandboxEnabledByUndeterminedPolicy = sandboxEnabledByUndeterminedPolicy, ServerFetchFailed = serverFetchFailed, DeviceLoadFailed = deviceLoadFailed, ServerResponse = CopilotClient.ToJsonElementForWire(serverResponse), DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), DeviceSandboxFloor = CopilotClient.ToJsonElementForWire(deviceSandboxFloor), SharedSandboxFloor = CopilotClient.ToJsonElementForWire(sharedSandboxFloor), PolicyHelperResponse = CopilotClient.ToJsonElementForWire(policyHelperResponse) }; + await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.retainPolicy", [request], cancellationToken); } - /// Registers the calling SDK client as the per-entrypoint extension launch provider. Call before creating any sessions. When omitted, the runtime uses its built-in extension launcher. + /// Stamps an effective managed policy's individually-controlled entries onto a user settings document, returning the settings a host should actually act on. The managed layer wins on every plugin spec and marketplace name it names, and leaves everything it does not name as the user wrote it. Hosts use this rather than merging the two documents themselves, because the merge is per entry rather than per document and a whole-document overlay would either discard the user's unmanaged entries or let a user entry outrank a managed one. Omitting the managed layer returns the settings unchanged, which is what an unmanaged host wants. Rejects when either document is present but is not a JSON object rather than treating it as absent, since silently dropping a malformed policy hands the user's layer the win on exactly the entries the policy exists to control. + /// The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. + /// The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. /// The to monitor for cancellation requests. The default is . - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - public async Task RegisterExtensionLaunchProviderAsync(CancellationToken cancellationToken = default) + /// The user settings with the managed layer's controlled entries stamped on. + internal async Task ApplyControlsAsync(object? settings, object? managed = null, CancellationToken cancellationToken = default) { - await CopilotClient.InvokeRpcAsync(_rpc, "registerExtensionLaunchProvider", [], cancellationToken); + var request = new ManagedSettingsApplyControlsParams { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null"), Managed = CopilotClient.ToJsonElementForWire(managed) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.applyControls", [request], cancellationToken); } - /// Environments APIs. - public ServerEnvironmentsApi Environments => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Host APIs. - public ServerHostApi Host => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Hooks APIs. - public ServerHooksApi Hooks => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Validates the managed settings a client is supplying for a session it is about to open, and returns them reduced to the keys a client is allowed to set. A client-supplied policy is not the same thing as an administrator's: it may only narrow permissions, so this accepts `permissions` and rejects every other key outright rather than ignoring it. Rejecting is the point — a host that silently dropped an unsupported key would report a policy as applied while running without it. Hosts call this before opening the session rather than letting the open fail, so a malformed policy is reported against the request that carried it. The runtime applies the same rule again when the session starts, so this cannot be used to smuggle a wider document past it. An accepted document that sets nothing comes back as an empty object, which is distinct from supplying nothing at all. + /// The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. + /// The to monitor for cancellation requests. The default is . + /// The accepted managed settings, reduced to the keys a client is allowed to set. + internal async Task ParseClientValueAsync(object? settings = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsParseClientValueParams { Settings = CopilotClient.ToJsonElementForWire(settings) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.parseClientValue", [request], cancellationToken); + } - /// Models APIs. - public ServerModelsApi Models => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Composes the supplied server, device/MDM, device sandbox floor and policy-helper layers into the single effective managed policy a host should enforce, resolving each key across the layers by the runtime's own precedence rules. Hosts that assemble managed layers themselves use this so their precedence matches the runtime's exactly instead of reimplementing it. The composition is not a pure function of its inputs: an advisory sandbox force-on that arrived over the server channel is declined when this host cannot run a sandbox, so the result reflects the runtime host's capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when that happened. Enforced channels (device/MDM and policy helper) are never declined, and a server force-on carrying `failIfUnavailable` is preserved so the session fails loudly instead of quietly running unsandboxed. Rejects when a supplied layer is present but is not a JSON object, rather than treating it as unmanaged, because silently dropping a malformed policy would hand the user's own layer the win on exactly the keys the policy exists to control. + /// The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. + /// The device layer: native MDM and managed-file settings describing the machine rather than the account. + /// The device sandbox floor, folded into the device layer under `sandbox` before composition. + /// The policy-helper layer, an enforced channel sourced from a platform policy helper process. + /// The to monitor for cancellation requests. The default is . + /// The effective managed policy composed from the supplied layers. + internal async Task ResolveEffectiveValueAsync(object? server = null, object? mdm = null, object? deviceSandboxFloor = null, object? policyHelper = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsResolveEffectiveValueParams { Server = CopilotClient.ToJsonElementForWire(server), Mdm = CopilotClient.ToJsonElementForWire(mdm), DeviceSandboxFloor = CopilotClient.ToJsonElementForWire(deviceSandboxFloor), PolicyHelper = CopilotClient.ToJsonElementForWire(policyHelper) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveEffectiveValue", [request], cancellationToken); + } - /// Sandbox APIs. - public ServerSandboxApi Sandbox => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Decides what a host must do to its bypass-permissions state after a managed-policy resolution lands, given the state already in force and the account now signed in. A host holds two pieces of state — which layer disabled bypass mode, and for a server-delivered disable, the account it was pinned to — and cannot decide the next step from the new policy alone. Three rules make that so, and each one is a control rather than a preference. A device/MDM disable outranks the account, so a later server answer never lifts it. An unknown policy, which is what a failed fetch or a refusal this build cannot enforce yields, preserves whatever is in force instead of reverting to permissive. And a server disable is lifted only when the account it was pinned to is no longer the signed-in one, which is what makes signing in to an unrestricted account recover without a restart while a reconnect on the same restricted account does not. Hosts call this rather than reimplementing it because getting the pinning backwards either strands a disable on an account that never carried one or drops one that still applies. `setDisabledState` is omitted when the host must leave its stored flag untouched, which is distinct from being told to set it to false. + /// The account signed in now. A `managed` disable pinned to a different account is lifted. + /// What the resolution said about bypass mode. Send `unknown` rather than omitting the field when there is no verdict. + /// Which layer currently disables bypass mode. Omit it when nothing does. + /// The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. + /// The to monitor for cancellation requests. The default is . + /// The bypass-permissions state a host should hold after the resolution, and what it must do to get there. + internal async Task ResolveBypassDisableTransitionAsync(string activeIdentity, ManagedSettingsBypassPolicyResolution policy, ManagedSettingsBypassDisableSource? currentSource = null, string? currentManagedIdentity = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(activeIdentity); - /// Tools APIs. - public ServerToolsApi Tools => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsResolveBypassDisableTransitionParams { ActiveIdentity = activeIdentity, Policy = policy, CurrentSource = currentSource, CurrentManagedIdentity = currentManagedIdentity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveBypassDisableTransition", [request], cancellationToken); + } - /// Account APIs. - public ServerAccountApi Account => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Resolves managed (enterprise policy) settings for a host from every layer at once: the account's server-delivered policy, the device/MDM layer, and a platform policy helper. Hosts use this instead of fetching and composing the layers themselves, because the per-layer precedence and the fail-closed rules that apply when a layer cannot be confirmed are the runtime's own and must match the policy a session will later enforce. It does not retain or apply anything to process-global policy state, so a host may call it before any session exists — which is the point, since plugin activation and one-shot commands resolve policy before a session is available to carry it. The returned per-layer outcome flags are load-bearing rather than diagnostic: a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather than logging them, so a host that runs before a log sink exists still sees them. + /// User agent to send with the policy fetch. + /// The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + /// The host's home directory, used to resolve cache and managed-file locations. + /// The policy-helper invocation reason. Defaults to sessionStart. + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + /// The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + /// How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + /// Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. + /// The to monitor for cancellation requests. The default is . + /// The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + internal async Task IngestAsync(string userAgent, object? environment, string platform, string homeDirectory, ManagedSettingsPolicyHelperReason? policyHelperReason = null, bool? selfFetch = null, object? authInfo = null, string? sessionId = null, object? deviceResponse = null, bool? hasDeviceResponse = null, bool? bypassCacheRead = null, ManagedSettingsServerPolicyCacheMode? serverPolicyCacheMode = null, bool? policyHelperEnabled = null, string? policyHelperWorkingDirectory = null, string? clientName = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(userAgent); + ArgumentNullException.ThrowIfNull(platform); + ArgumentNullException.ThrowIfNull(homeDirectory); - /// Secrets APIs. - public ServerSecretsApi Secrets => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsIngestParams { UserAgent = userAgent, Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), Platform = platform, HomeDirectory = homeDirectory, PolicyHelperReason = policyHelperReason, SelfFetch = selfFetch, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo), SessionId = sessionId, DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), HasDeviceResponse = hasDeviceResponse, BypassCacheRead = bypassCacheRead, ServerPolicyCacheMode = serverPolicyCacheMode, PolicyHelperEnabled = policyHelperEnabled, PolicyHelperWorkingDirectory = policyHelperWorkingDirectory, ClientName = clientName }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.ingest", [request], cancellationToken); + } + + /// Resolves the managed (enterprise policy) settings a host must enforce from startup, and judges the account against the enterprise sign-in pin in the same pass. This composes the layers the way `managedSettings.ingest` does and then answers the two questions a host cannot answer for itself: which fail-closed floors apply when a layer could not be confirmed, and whether this credential is allowed to sign in at all. The sign-in verdict is the reason a host must not assemble this itself from `managedSettings.ingest` — a pinned organization is an access control, and a host that composed the layers but skipped the pin would let a developer sign in with a personal or another enterprise's account and escape every control that keys off the signed-in identity. The verdict is computed on every resolution, including one that is not retained, so declining to apply policy never widens access. Set `retainAndApply` to keep the resolved policy as this runtime process's startup policy; leave it false to resolve without side effects. + /// User agent to send with the policy fetch. + /// The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + /// The host's home directory, used to resolve cache and managed-file locations. + /// Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. + /// The policy-helper invocation reason. Defaults to sessionStart. + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. + /// The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + /// How this resolution may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two express the same decision and accepting both would leave the caller unsure which one the runtime honored. + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + /// Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. + /// The to monitor for cancellation requests. The default is . + /// The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + internal async Task ResolveStartupPolicyAsync(string userAgent, object? environment, string platform, string homeDirectory, bool retainAndApply, ManagedSettingsPolicyHelperReason? policyHelperReason = null, bool? selfFetch = null, object? authInfo = null, string? sessionId = null, object? deviceResponse = null, bool? hasDeviceResponse = null, bool? bypassCacheRead = null, ManagedSettingsServerPolicyCacheMode? serverPolicyCacheMode = null, bool? policyHelperEnabled = null, string? policyHelperWorkingDirectory = null, string? clientName = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(userAgent); + ArgumentNullException.ThrowIfNull(platform); + ArgumentNullException.ThrowIfNull(homeDirectory); - /// Mcp APIs. - public ServerMcpApi Mcp => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsResolveStartupPolicyParams { UserAgent = userAgent, Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), Platform = platform, HomeDirectory = homeDirectory, RetainAndApply = retainAndApply, PolicyHelperReason = policyHelperReason, SelfFetch = selfFetch, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo), SessionId = sessionId, DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), HasDeviceResponse = hasDeviceResponse, BypassCacheRead = bypassCacheRead, ServerPolicyCacheMode = serverPolicyCacheMode, PolicyHelperEnabled = policyHelperEnabled, PolicyHelperWorkingDirectory = policyHelperWorkingDirectory, ClientName = clientName }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveStartupPolicy", [request], cancellationToken); + } - /// Extensions APIs. - public ServerExtensionsApi Extensions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Resolves the managed `remoteControl` policy for an account on its own, for a host deciding whether a remote-control session may start. Composes the same layers as `managedSettings.ingest` and returns only that one key, so a host does not have to know which layer won. An absent policy means the account is unmanaged for this capability and the host may proceed; that default is safe only while absence really does mean "no policy", so a service refusal that says an account policy exists which this client is too old to enforce resolves to an explicit disabled policy instead of to absence. A resolution that cannot be completed is rejected rather than answered as absence, for the same reason. + /// User agent to send with the policy fetch. + /// The host's environment variables, read for cache location and policy overrides. + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + /// The host's home directory, used to resolve cache and managed-file locations. + /// The policy-helper invocation reason. Defaults to sessionStart. + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. + /// The to monitor for cancellation requests. The default is . + /// The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. + internal async Task LoadRemoteControlAsync(string userAgent, object? environment, string platform, string homeDirectory, ManagedSettingsPolicyHelperReason? policyHelperReason = null, bool? selfFetch = null, object? authInfo = null, object? deviceResponse = null, bool? hasDeviceResponse = null, bool? policyHelperEnabled = null, string? clientName = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(userAgent); + ArgumentNullException.ThrowIfNull(platform); + ArgumentNullException.ThrowIfNull(homeDirectory); + + var request = new ManagedSettingsLoadRemoteControlParams { UserAgent = userAgent, Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), Platform = platform, HomeDirectory = homeDirectory, PolicyHelperReason = policyHelperReason, SelfFetch = selfFetch, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo), DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), HasDeviceResponse = hasDeviceResponse, PolicyHelperEnabled = policyHelperEnabled, ClientName = clientName }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.loadRemoteControl", [request], cancellationToken); + } + + /// Evaluates the device-channel enterprise sign-in pin (MDM plist, registry, or managed-settings file) against a credential, without resolving any server-delivered policy. This is the gate an entry point runs before it branches, and the only one that can refuse a developer's first sign-in: it is local, needs no credential, and a server-delivered pin only ever reaches accounts already inside the organization. It fails closed by construction — a discovery that cannot determine whether a pin exists refuses rather than allows, because a control that fails open under a triggerable condition is not a control. Hosts that also want the server channel should call `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. + /// The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. + /// The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. + /// The to monitor for cancellation requests. The default is . + /// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. + internal async Task ResolveDeviceForceLoginOrgsGateAsync(object? environment, object? authInfo = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsResolveDeviceForceLoginOrgsGateParams { Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), AuthInfo = CopilotClient.ToJsonElementForWire(authInfo) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveDeviceForceLoginOrgsGate", [request], cancellationToken); + } - /// Skills APIs. - public ServerSkillsApi Skills => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. + /// The to monitor for cancellation requests. The default is . + /// Validated device-managed settings discovered before a session exists. + public async Task ReadAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.read", [], cancellationToken); + } - /// Catalog APIs. - public ServerCatalogApi Catalog => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `<cacheHome>/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. + /// The to monitor for cancellation requests. The default is . + public async Task ClearCacheAsync(CancellationToken cancellationToken = default) + { + await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.clearCache", [], cancellationToken); + } - /// Plugins APIs. - public ServerPluginsApi Plugins => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. + /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. + /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. + /// Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. + /// The to monitor for cancellation requests. The default is . + /// Effective enterprise managed settings for an account, resolved without a session. + public async Task ResolveAsync(string? selectionId = null, string? gitHubToken = null, string? clientName = null, string? workingDirectory = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsResolveRequest { SelectionId = selectionId, GitHubToken = gitHubToken, ClientName = clientName, WorkingDirectory = workingDirectory }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolve", [request], cancellationToken); + } - /// Agents APIs. - public ServerAgentsApi Agents => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Compatibility overload preserving the positional CancellationToken parameter from before workingDirectory was added. + public Task ResolveAsync(string? selectionId, string? gitHubToken, string? clientName, CancellationToken cancellationToken) + => ResolveAsync(selectionId, gitHubToken, clientName, workingDirectory: null, cancellationToken); - /// Instructions APIs. - public ServerInstructionsApi Instructions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. + /// The to monitor for cancellation requests. The default is . + /// The authoring JSON schema for managed settings recognized by this runtime. + public async Task SchemaAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.schema", [], cancellationToken); + } - /// Commands APIs. - public ServerCommandsApi Commands => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. + /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. + /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. + /// The to monitor for cancellation requests. The default is . + /// Result of validating a managed-settings document. + public async Task ValidateAsync(object? content, string? layer = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsValidateRequest { Content = CopilotClient.ToJsonElementForWire(content) ?? JsonElement.Parse("null"), Layer = layer }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.validate", [request], cancellationToken); + } - /// User APIs. - public ServerUserApi User => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. + /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. + /// The to monitor for cancellation requests. The default is . + /// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. + public async Task ComposeAsync(IList layers, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(layers); - /// ManagedSettings APIs. - public ServerManagedSettingsApi ManagedSettings => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsComposeRequest { Layers = layers }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.compose", [request], cancellationToken); + } - /// Runtime APIs. - public ServerRuntimeApi Runtime => + /// Permissions APIs. + public ServerManagedSettingsPermissionsApi Permissions => field ?? Interlocked.CompareExchange(ref field, new(_rpc), null) ?? field; +} - /// SessionFs APIs. - public ServerSessionFsApi SessionFs => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; +/// Provides server-scoped ManagedSettingsPermissions APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerManagedSettingsPermissionsApi +{ + private readonly JsonRpc _rpc; - /// LlmInference APIs. - public ServerLlmInferenceApi LlmInference => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + internal ServerManagedSettingsPermissionsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Sessions APIs. - public ServerSessionsApi Sessions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. + /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + /// The to monitor for cancellation requests. The default is . + /// Ordered managed permission verdicts and the supplied policy's fail-closed posture. + public async Task EvaluateAsync(ManagedPermissionsContext context, IList operations, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(operations); - /// AgentRegistry APIs. - public ServerAgentRegistryApi AgentRegistry => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsPermissionsEvaluateRequest { Context = context, Operations = operations }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.permissions.evaluate", [request], cancellationToken); + } } /// Provides server-scoped Environments APIs. @@ -42201,18 +48072,35 @@ public async Task PublishSessionAsync(string hostId, s return await CopilotClient.InvokeRpcAsync(_rpc, "host.publishSession", [request], cancellationToken); } + /// Reads the complete advertised live and dormant session catalog of an existing host owned by this connection. Does not start hosting, subscribe to sessions, or guarantee resumability. + /// + /// Listener UUID returned by host.start; the caller must own it. Omit to read + /// the saved default compute-identity catalog without starting a listener. + /// + /// The to monitor for cancellation requests. The default is . + /// The complete live and dormant advertised catalog, without subscribing to sessions. + public async Task ListSessionsAsync(string? hostId = null, CancellationToken cancellationToken = default) + { + var request = new HostListSessionsRequest { HostId = hostId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "host.listSessions", [request], cancellationToken); + } + /// Requests app-owned materialization over the owning SDK participant. /// Unique identity for this participation, independent of the session lifetime. /// Host-selected SDK creation or resume settings, without executable callbacks or tools. /// Resume an app-owned durable session instead of creating a new session. + /// + /// For an explicit publication, borrow an existing owning-connection resident + /// instead of invoking the resume factory. Cold sessions still use the factory. + /// /// The to monitor for cancellation requests. The default is . /// The resident session the application has materialized on its own connection. - internal async Task CreateSessionAsync(string handoffId, IDictionary config, bool? resume = null, CancellationToken cancellationToken = default) + internal async Task CreateSessionAsync(string handoffId, IDictionary config, bool? resume = null, bool? preferResident = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(handoffId); ArgumentNullException.ThrowIfNull(config); - var request = new HostCreateSessionRequest { HandoffId = handoffId, Config = config, Resume = resume }; + var request = new HostCreateSessionRequest { HandoffId = handoffId, Config = config, Resume = resume, PreferResident = preferResident }; return await CopilotClient.InvokeRpcAsync(_rpc, "host.createSession", [request], cancellationToken); } @@ -42244,6 +48132,17 @@ public async Task StartAsync(string hostId, HostLocalServerOpti return await CopilotClient.InvokeRpcAsync(_rpc, "host.start", [request], cancellationToken); } + /// Starts a connection-owned AHP host with explicit localServer and/or githubEnvironment transports as a supervised SDK participant. + /// Starts a supervised AHP host with at least one explicitly selected transport. + /// The to monitor for cancellation requests. The default is . + /// Listener readiness, returned only after binding and the supervised participant's SDK handshake. + public async Task StartAsync(HostStartRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + ArgumentNullException.ThrowIfNull(request.HostId); + return await CopilotClient.InvokeRpcAsync(_rpc, "host.start", [request], cancellationToken); + } + /// Stops a listener owned by this SDK connection and joins its cleanup without deleting sessions. /// Listener UUID. Unknown or successfully stopped IDs are harmless. /// The to monitor for cancellation requests. The default is . @@ -42306,6 +48205,16 @@ public async Task DiscoverAsync(IList? projectPaths var request = new HooksDiscoverRequest { ProjectPaths = projectPaths, ExcludeHostHooks = excludeHostHooks }; return await CopilotClient.InvokeRpcAsync(_rpc, "hooks.discover", [request], cancellationToken); } + + /// Discovers hook actions enabled under server-side discovery settings from user, repository, plugin, and managed-policy sources. + /// Optional project paths and host-exclusion behavior for server-scoped hook discovery. + /// The to monitor for cancellation requests. The default is . + /// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. + public async Task DiscoverAsync(HooksDiscoverRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "hooks.discover", [request], cancellationToken); + } } /// Provides server-scoped Models APIs. @@ -42339,92 +48248,6 @@ public async Task GetBuiltInCatalogAsync(CancellationToken } } -/// Provides server-scoped Sandbox APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSandboxApi -{ - private readonly JsonRpc _rpc; - - internal ServerSandboxApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. - /// The to monitor for cancellation requests. The default is . - /// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. - public async Task GetHostSupportAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getHostSupport", [], cancellationToken); - } - - /// ProxyCa APIs. - public ServerSandboxProxyCaApi ProxyCa => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; -} - -/// Provides server-scoped SandboxProxyCa APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSandboxProxyCaApi -{ - private readonly JsonRpc _rpc; - - internal ServerSandboxProxyCaApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task GetStatusAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.getStatus", [request], cancellationToken); - } - - /// Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Result of creating the persistent certificate authority of the sandbox credential proxy. - public async Task CreateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.create", [request], cancellationToken); - } - - /// Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task RotateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.rotate", [request], cancellationToken); - } - - /// Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task TrustAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.trust", [request], cancellationToken); - } - - /// Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task RemoveAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.remove", [], cancellationToken); - } -} - /// Provides server-scoped Tools APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerToolsApi @@ -42510,6 +48333,51 @@ public async Task LogoutAsync(string? selectionId = null, A var request = new AccountLogoutRequest { SelectionId = selectionId, AuthInfo = authInfo }; return await CopilotClient.InvokeRpcAsync(_rpc, "account.logout", [request], cancellationToken); } + + /// Renders the sign-in banner and the one-line account description the runtime uses for an authentication identity. The runtime words these in several places for its own callers, so a host that announces a sign-in or an account switch should render them from here rather than composing its own, which would let the two spellings drift apart. + /// Identity to describe. + /// The to monitor for cancellation requests. The default is . + /// The wording the runtime uses for an authentication identity. + internal async Task DescribeAuthInfoAsync(AuthIdentity identity, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(identity); + + var request = new AccountDescribeAuthInfoRequest { Identity = identity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "account.describeAuthInfo", [request], cancellationToken); + } + + /// Reports whether the supplied identity can create gists. Gists are unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed Users on github.com, so a host that offers gist actions should hide or disable them when this reports no support. + /// Identity to evaluate. + /// The to monitor for cancellation requests. The default is . + /// Whether the identity can create gists, and why not when it cannot. + internal async Task GetGistSupportAsync(AuthIdentity identity, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(identity); + + var request = new AccountGetGistSupportRequest { Identity = identity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "account.getGistSupport", [request], cancellationToken); + } + + /// Resolves a path on the identity's GitHub host into an absolute URL, so a host can link to settings or documentation on the enterprise instance the user is signed in to rather than to github.com. Falls back to the public host when no identity is supplied. + /// Host-relative path, without a leading slash, for example `settings/copilot/features`. + /// Identity whose host the path resolves against. Omit to resolve against the public github.com host. + /// The to monitor for cancellation requests. The default is . + /// An absolute URL on the identity's GitHub host. + internal async Task GetWebUrlAsync(string path, AuthIdentity? identity = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(path); + + var request = new AccountGetWebUrlRequest { Path = path, Identity = identity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "account.getWebUrl", [request], cancellationToken); + } + + /// Names the environment variable supplying a classic personal access token, if one is set. A classic token cannot be upgraded in place, so a host that finds one should tell the user which variable to unset rather than starting an interactive sign-in that the variable would override. + /// The to monitor for cancellation requests. The default is . + /// The environment variable supplying a classic personal access token, when one is set. + internal async Task GetTokenEnvVarAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "account.getTokenEnvVar", [], cancellationToken); + } } /// Provides server-scoped Secrets APIs. @@ -42558,6 +48426,26 @@ public async Task DiscoverAsync(string? workingDirectory = nu return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.discover", [request], cancellationToken); } + /// Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + /// The to monitor for cancellation requests. The default is . + /// Names of the MCP servers the runtime supplies itself. + internal async Task ListBuiltinServerNamesAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.listBuiltinServerNames", [], cancellationToken); + } + + /// Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. + /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + /// How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + /// The to monitor for cancellation requests. The default is . + /// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + internal async Task ShouldExcludeGitHubToolsAsync(IList? availableTools = null, IList? excludedTools = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, CancellationToken cancellationToken = default) + { + var request = new McpShouldExcludeGitHubToolsRequest { AvailableTools = availableTools, ExcludedTools = excludedTools, ToolFilterPrecedence = toolFilterPrecedence }; + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.shouldExcludeGitHubTools", [request], cancellationToken); + } + /// Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. /// Protocol version and capabilities the caller requires. /// What to plan: either a candidate handle from a previous search, or a card supplied directly. @@ -42670,6 +48558,12 @@ public async Task ApplyUninstallAsync(CatalogClientContra Interlocked.CompareExchange(ref field, new(_rpc), null) ?? field; + /// Registry APIs. + public ServerMcpRegistryApi Registry => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + /// Installations APIs. public ServerMcpInstallationsApi Installations => field ?? @@ -42700,12 +48594,11 @@ public async Task ListAsync(CancellationToken cancellationToken = /// Unique name for the MCP server. /// MCP server configuration (stdio process or remote HTTP/SSE). /// The to monitor for cancellation requests. The default is . - public async Task AddAsync(string name, object config, CancellationToken cancellationToken = default) + public async Task AddAsync(string name, object? config, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(config); - var request = new McpConfigAddRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config)!.Value }; + var request = new McpConfigAddRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config) ?? JsonElement.Parse("null") }; await CopilotClient.InvokeRpcAsync(_rpc, "mcp.config.add", [request], cancellationToken); } @@ -42713,12 +48606,11 @@ public async Task AddAsync(string name, object config, CancellationToken cancell /// Name of the MCP server to update. /// MCP server configuration (stdio process or remote HTTP/SSE). /// The to monitor for cancellation requests. The default is . - public async Task UpdateAsync(string name, object config, CancellationToken cancellationToken = default) + public async Task UpdateAsync(string name, object? config, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(config); - var request = new McpConfigUpdateRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config)!.Value }; + var request = new McpConfigUpdateRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config) ?? JsonElement.Parse("null") }; await CopilotClient.InvokeRpcAsync(_rpc, "mcp.config.update", [request], cancellationToken); } @@ -42764,6 +48656,50 @@ public async Task ReloadAsync(CancellationToken cancellationToken = default) } } +/// Provides server-scoped McpRegistry APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerMcpRegistryApi +{ + private readonly JsonRpc _rpc; + + internal ServerMcpRegistryApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + /// The to monitor for cancellation requests. The default is . + /// Request id naming a cancellable registry search. + internal async Task AllocateRequestIdAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.registry.allocateRequestId", [], cancellationToken); + } + + /// Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + /// Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. + /// The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. + /// Maximum number of servers to return. + /// Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. + /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. + /// The to monitor for cancellation requests. The default is . + /// Servers selected from the registry response. + internal async Task SearchAsync(long requestId, object? authInfo, long limit, string? query = null, string? repository = null, CancellationToken cancellationToken = default) + { + var request = new McpRegistrySearchRequest { RequestId = requestId, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo) ?? JsonElement.Parse("null"), Limit = limit, Query = query, Repository = repository }; + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.registry.search", [request], cancellationToken); + } + + /// Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + /// Request ID from `mcp.registry.allocateRequestId` that the search uses. + /// The to monitor for cancellation requests. The default is . + /// Whether the cancel reached a live search. + internal async Task CancelAsync(long requestId, CancellationToken cancellationToken = default) + { + var request = new McpRegistryCancelRequest { RequestId = requestId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.registry.cancel", [request], cancellationToken); + } +} + /// Provides server-scoped McpInstallations APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerMcpInstallationsApi @@ -42874,6 +48810,92 @@ public async Task DisableAsync(IList ids, CancellationToken cancellation } } +/// Provides server-scoped Instructions APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerInstructionsApi +{ + private readonly JsonRpc _rpc; + + internal ServerInstructionsApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Returns the prompt the `init` command runs to author repository instructions. A host offering its own initialize action sends this text so the instructions it produces match the ones the CLI produces. The text is fixed for a build and depends on no configuration, session or repository. + /// The to monitor for cancellation requests. The default is . + /// The prompt the init command runs. + internal async Task GetInitPromptAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getInitPrompt", [], cancellationToken); + } + + /// Discovers instruction sources across user, repository, and plugin sources. + /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + /// The to monitor for cancellation requests. The default is . + /// Instruction sources discovered across user, repository, and plugin sources. + public async Task DiscoverAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) + { + var request = new InstructionsDiscoverRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discover", [request], cancellationToken); + } + + /// Discovers instruction sources across user, repository, and plugin sources. + /// Optional project paths to include in instruction discovery. + /// The to monitor for cancellation requests. The default is . + /// Instruction sources discovered across user, repository, and plugin sources. + public async Task DiscoverAsync(InstructionsDiscoverRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discover", [request], cancellationToken); + } + + /// Discovers the instruction sources for one caller-named location and returns them in the order the runtime applies them. `discover` answers for a set of project paths and derives the rest of its scope itself; this one instead takes every argument from the caller — the extra directories to scan and whether to descend into nested instruction files — and honors them as given. It also includes instruction directories from trusted repository settings, matching native repository discovery. Use it when the caller knows its own scope and no session exists to derive that scope from, such as a host reporting how many instruction files a directory contributes before any session starts. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. + /// When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. + /// Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. + /// Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. + /// Extra directories to scan alongside instruction directories configured in the runtime environment. + /// When true, also discover instruction files nested below the location. + /// The to monitor for cancellation requests. The default is . + /// Instruction sources discovered across user, repository, and plugin sources. + internal async Task DiscoverRepoSourcesAsync(string location, bool? isCli = null, string? cwdPath = null, string? configDir = null, IList? additionalDirs = null, bool? enableChildInstructions = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(location); + + var request = new InstructionsDiscoverRepoSourcesRequest { Location = location, IsCli = isCli, CwdPath = cwdPath, ConfigDir = configDir, AdditionalDirs = additionalDirs, EnableChildInstructions = enableChildInstructions }; + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discoverRepoSources", [request], cancellationToken); + } + + /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + /// The to monitor for cancellation requests. The default is . + /// Canonical files and directories where custom instructions can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) + { + var request = new InstructionsGetDiscoveryPathsRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getDiscoveryPaths", [request], cancellationToken); + } + + /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + /// Optional project paths to include when enumerating instruction discovery targets. + /// The to monitor for cancellation requests. The default is . + /// Canonical files and directories where custom instructions can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(InstructionsGetDiscoveryPathsRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getDiscoveryPaths", [request], cancellationToken); + } + + /// Drops the runtime's in-memory cache of discovered custom instructions so the next discovery reads them from disk again. A host calls this after it changes instruction files, or after it trusts a folder whose instructions an earlier discovery skipped, so that a session started afterwards sees the current files instead of a cached earlier answer. The call performs no I/O of its own and removes nothing from disk; it only invalidates, so the cost lands on the next discovery. Returns once the cache is clear, which is what lets a caller order a session start after it. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// The to monitor for cancellation requests. The default is . + internal async Task ClearCacheAsync(CancellationToken cancellationToken = default) + { + await CopilotClient.InvokeRpcAsync(_rpc, "instructions.clearCache", [], cancellationToken); + } +} + /// Provides server-scoped Skills APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerSkillsApi @@ -42951,7 +48973,7 @@ public async Task ApplyUninstallAsync(CatalogClientCont /// Discovers skills across global and project sources. /// Optional list of project directory paths to scan for project-scoped skills. - /// Optional list of additional skill directory paths to include. + /// Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. /// Optional skill scan paths to exclude from discovery. /// When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. /// The to monitor for cancellation requests. The default is . @@ -42974,6 +48996,16 @@ public async Task GetDiscoveryPathsAsync(IList? return await CopilotClient.InvokeRpcAsync(_rpc, "skills.getDiscoveryPaths", [request], cancellationToken); } + /// Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + /// Optional project paths to enumerate. + /// The to monitor for cancellation requests. The default is . + /// Canonical locations where skills can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(SkillsGetDiscoveryPathsRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "skills.getDiscoveryPaths", [request], cancellationToken); + } + /// Installations APIs. public ServerSkillsInstallationsApi Installations => field ?? @@ -43379,6 +49411,16 @@ public async Task DiscoverAsync(IList? projectPaths = n return await CopilotClient.InvokeRpcAsync(_rpc, "agents.discover", [request], cancellationToken); } + /// Discovers custom agents across user, project, plugin, and remote sources. + /// Optional project paths to include in agent discovery. + /// The to monitor for cancellation requests. The default is . + /// Agents discovered across user, project, plugin, and remote sources. + public async Task DiscoverAsync(AgentsDiscoverRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.discover", [request], cancellationToken); + } + /// Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. /// Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). @@ -43389,39 +49431,116 @@ public async Task GetDiscoveryPathsAsync(IList? var request = new AgentsGetDiscoveryPathsRequest { ProjectPaths = projectPaths, ExcludeHostAgents = excludeHostAgents }; return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getDiscoveryPaths", [request], cancellationToken); } + + /// Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + /// Optional project paths to include when enumerating agent discovery directories. + /// The to monitor for cancellation requests. The default is . + /// Canonical locations where custom agents can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(AgentsGetDiscoveryPathsRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getDiscoveryPaths", [request], cancellationToken); + } + + /// Lists the agents this runtime ships, by name. A consumer separating shipped agents from ones the user or a plugin authored should compare against these names rather than against `AgentInfo.source`: an authored agent may carry the `builtin` source while not being one of these, and the runtime treats the two as separate questions. `disableableNames` is the subset a user may turn off, which a client needs to decide whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML definition, which a client needs before asking the runtime to load one. + /// The to monitor for cancellation requests. The default is . + /// The agents this runtime ships, named so a consumer can tell them apart from authored ones. + internal async Task GetBuiltinsAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getBuiltins", [], cancellationToken); + } + + /// Lists the shipped agents a client should offer right now, filtered by the feature flags it passes. `getBuiltins` names every agent the runtime knows about; some of those are gated, so a client rendering a picker wants this narrower list together with the description to show beside each name. + /// Feature flag values keyed by name, evaluated with the runtime's truthiness rules. Omit or pass null for no flags. + /// Flag overrides keyed by name. A null entry uses the corresponding base flag; false explicitly disables it. Omit or pass null for no overrides. + /// The surface asking, which gates agents that only apply to one client. Omit or pass null to apply no client filter. + /// The to monitor for cancellation requests. The default is . + /// The shipped agents available under the requested flags. + internal async Task GetAvailableBuiltinsAsync(IDictionary? featureFlags = null, IDictionary? overrides = null, string? context = null, CancellationToken cancellationToken = default) + { + var request = new AgentsGetAvailableBuiltinsRequest { FeatureFlags = featureFlags, Overrides = overrides, Context = context }; + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getAvailableBuiltins", [request], cancellationToken); + } + + /// Loads one shipped agent's YAML definition, for a client that needs what the agent declares rather than only its name. `getBuiltins` reports which names have a definition to load: a name outside its `yamlBasedNames` is special-cased in code and has none. The definition crosses as its own JSON rather than as contract-typed fields, because the runtime parses it with the agent schema's tolerant shape and re-typing it here would drop the keys that shape accepts and this one does not. The projected `__nativeCustomAgent` view the runtime derives is included, so a caller reading the declared model and a caller rendering the agent see the same definition. + /// The agent name, which must be one of `getBuiltins`'s `yamlBasedNames`. A name outside that list is special-cased in code and has no definition, and is reported as an error rather than as an empty definition. + /// The to monitor for cancellation requests. The default is . + /// One shipped agent's definition. + internal async Task GetBuiltinDefinitionAsync(string name, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(name); + + var request = new AgentsGetBuiltinDefinitionRequest { Name = name }; + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getBuiltinDefinition", [request], cancellationToken); + } + + /// Projects one shipped agent the way a picker lists it, reading only the metadata at the head of the definition file and stopping before the prompt body. `getBuiltinDefinition` answers the whole definition instead, so a client listing every shipped agent should prefer this one: the cost of a listing grows with the number of agents, and the prompt body is the part a listing never shows. The two also differ in shape. This returns the projected custom agent on its own, whereas `getBuiltinDefinition` returns the authored definition with that projection nested under `__nativeCustomAgent`. + /// The agent name, taken from `getAvailableBuiltins`. Unlike `getBuiltinDefinition`, the agent that `getBuiltins` reports as special-cased rather than YAML-based is answered here too, from its in-code definition. + /// The to monitor for cancellation requests. The default is . + /// One shipped agent, projected for a listing. + internal async Task GetBuiltinListingDefinitionAsync(string name, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(name); + + var request = new AgentsGetBuiltinListingDefinitionRequest { Name = name }; + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getBuiltinListingDefinition", [request], cancellationToken); + } + + /// Resolves the model a custom agent asks for against the models actually available, and answers both the model to switch to and the warning a user should see when the agent's preference cannot be met. A custom agent may name several acceptable models in preference order, so the decision is a match rather than a lookup, and an agent whose preference is unavailable is a normal outcome that produces a warning rather than an error. A host must call this rather than pick the first available name itself, because the preference order and the wording of the warning are what keep one installation's agent selection the same as another's. + /// The agent's declared `model:` entry, serialized. A single name or an ordered list of acceptable names. + /// The models available to this session, serialized in the shape the model list carries. + /// The to monitor for cancellation requests. The default is . + /// The model to switch to, and the warning to show when the agent's preference could not be met. + internal async Task CustomAgentInitialModelDecisionAsync(string agentModelsJson, string availableModelsJson, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(agentModelsJson); + ArgumentNullException.ThrowIfNull(availableModelsJson); + + var request = new AgentsCustomAgentInitialModelDecisionParams { AgentModelsJson = agentModelsJson, AvailableModelsJson = availableModelsJson }; + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.customAgentInitialModelDecision", [request], cancellationToken); + } } -/// Provides server-scoped Instructions APIs. +/// Provides server-scoped GlobalState APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerInstructionsApi +public sealed class ServerGlobalStateApi { private readonly JsonRpc _rpc; - internal ServerInstructionsApi(JsonRpc rpc) + internal ServerGlobalStateApi(JsonRpc rpc) { _rpc = rpc; } - /// Discovers instruction sources across user, repository, and plugin sources. - /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). - /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + /// Reads the host's machine-wide state: which plugins are installed and the one-off flags and timestamps that record what the user has already been shown or migrated. This is the state that outlives a single session and a single workspace, so a host reads it to decide whether to run a first-launch step, offer an onboarding prompt, or skip one it has already completed. The stored credentials are deliberately not part of this result; a caller that needs an authenticated identity asks the account methods for it instead. Reading is non-destructive and every field is optional, because a fresh install has recorded nothing yet. /// The to monitor for cancellation requests. The default is . - /// Instruction sources discovered across user, repository, and plugin sources. - public async Task DiscoverAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) + /// The host's machine-wide state. Every field is optional because a fresh install has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. + internal async Task LoadAsync(CancellationToken cancellationToken = default) { - var request = new InstructionsDiscoverRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; - return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discover", [request], cancellationToken); + return await CopilotClient.InvokeRpcAsync(_rpc, "globalState.load", [], cancellationToken); } - /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. - /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. - /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + /// Reads the host's machine-wide state exactly as `globalState.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the state read matches the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `globalState.load`. The stored credentials are omitted here for the same reason they are omitted from `globalState.load`: a caller that needs an authenticated identity asks the account methods instead, so pointing this at another directory cannot be used to read the credentials kept in it. + /// Copilot configuration directory to read the state document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. /// The to monitor for cancellation requests. The default is . - /// Canonical files and directories where custom instructions can be created so the runtime will recognize them. - public async Task GetDiscoveryPathsAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) + /// The host's machine-wide state. Every field is optional because a fresh install has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. + internal async Task LoadForConfigDirAsync(string? configDir = null, CancellationToken cancellationToken = default) { - var request = new InstructionsGetDiscoveryPathsRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; - return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getDiscoveryPaths", [request], cancellationToken); + var request = new GlobalStateLoadForConfigDirRequest { ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "globalState.loadForConfigDir", [request], cancellationToken); + } + + /// Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. + /// Top-level key to write, named as it appears in the result of `globalState.load`. It must be one of the writable keys that `globalState.writeKey` lists. + /// Copilot configuration directory to write the state document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to write the directory the server resolved for itself. Mirrors `globalState.loadForConfigDir`, so a caller can read and write the same directory. + /// Value to store for the key. Omit it, or pass null, to remove the key instead. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteKeyAsync(string key, string? configDir = null, object? value = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); + + var request = new GlobalStateWriteKeyRequest { Key = key, ConfigDir = configDir, Value = CopilotClient.ToJsonElementForWire(value) }; + await CopilotClient.InvokeRpcAsync(_rpc, "globalState.writeKey", [request], cancellationToken); } } @@ -43445,132 +49564,116 @@ public async Task ListAsync(CancellationToken cancellationToken = d } } -/// Provides server-scoped User APIs. +/// Provides server-scoped GitHubRepository APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerUserApi +public sealed class ServerGitHubRepositoryApi { private readonly JsonRpc _rpc; - internal ServerUserApi(JsonRpc rpc) + internal ServerGitHubRepositoryApi(JsonRpc rpc) { _rpc = rpc; } - /// Settings APIs. - public ServerUserSettingsApi Settings => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Resolves the GitHub repository that owns a working-tree path by reading the selected git remote configured for it, preferring `origin`. Returns a null `repository` when the path is inside a git working tree but that selected remote does not resolve to a GitHub host. Fails when the path is not inside a git working tree at all, so a caller can tell 'not a repository' apart from 'a repository with no GitHub remote'. + /// Absolute path to a directory inside the git working tree to resolve. + /// The to monitor for cancellation requests. The default is . + /// The GitHub repository that owns the requested path, when the selected remote (`origin`, else the first) is on a GitHub host. + internal async Task AtPathAsync(string path, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(path); + + var request = new GitHubRepositoryAtPathRequest { Path = path }; + return await CopilotClient.InvokeRpcAsync(_rpc, "gitHubRepository.atPath", [request], cancellationToken); + } } -/// Provides server-scoped UserSettings APIs. +/// Provides server-scoped GitHubOwners APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerUserSettingsApi +public sealed class ServerGitHubOwnersApi { private readonly JsonRpc _rpc; - internal ServerUserSettingsApi(JsonRpc rpc) + internal ServerGitHubOwnersApi(JsonRpc rpc) { _rpc = rpc; } - /// Drops this runtime process's in-memory user settings cache so the next settings read observes disk. + /// Registers a cancellable owner listing and returns its request id. Separate from `gitHubOwners.list` so the id exists before the listing starts: a caller that abandons the listing the moment it begins would otherwise have nothing to name in `gitHubOwners.cancel`. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. /// The to monitor for cancellation requests. The default is . - public async Task ReloadAsync(CancellationToken cancellationToken = default) + /// A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. + internal async Task NextRequestIdAsync(CancellationToken cancellationToken = default) { - await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.reload", [], cancellationToken); + return await CopilotClient.InvokeRpcAsync(_rpc, "gitHubOwners.nextRequestId", [], cancellationToken); } - /// Lists every known user setting (settings.json overlaid with the legacy config.json, config.json wins), each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. + /// Lists the logins the authenticated user may act as — their own account first, then the organizations they belong to — by asking the GitHub API under the supplied credential. No credential travels in the request: `authInfo` selects one the runtime already holds, and the runtime resolves the token and the GitHub host from it. A failure the caller should render arrives as `message`; one it should raise arrives as `throwError`. + /// Request id from `gitHubOwners.nextRequestId`. An id that was never registered, canceled before use, released after being abandoned, or already used is refused rather than silently running uncancellable. + /// The credential the listing runs under, carried opaquely because its shape is the host's own and the runtime only resolves a token and a GitHub host from it. No credential travels: this selects one the runtime already holds. /// The to monitor for cancellation requests. The default is . - /// Per-key metadata for every known user setting (settings.json overlaid with the legacy config.json, config.json wins), including settings left at their default. Excludes repository- and enterprise-managed overrides. - public async Task GetAsync(CancellationToken cancellationToken = default) + /// Outcome of an owner listing. Exactly one of `owners` and `message` is present, except that `throwError` reports a failure the caller is expected to raise rather than render. + internal async Task ListAsync(long requestId, object? authInfo, CancellationToken cancellationToken = default) { - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.get", [], cancellationToken); + var request = new GitHubOwnersListRequest { RequestId = requestId, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync(_rpc, "gitHubOwners.list", [request], cancellationToken); } - /// Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. Returns the keys whose new value is shadowed by a legacy config.json entry (config.json wins on read), which the runtime leaves in place — such writes do not take effect until the legacy value is removed. - /// Partial user settings to write, as a free-form object keyed by setting name. + /// Abandons an owner listing started with the given request id. Answers `canceled: true` while a listing with that id is running. Answers `canceled: false` when the id was never registered, was registered but not used, was released after being abandoned, or its listing has ended. Canceling an unused id releases it, and a later `list` with that id is refused. The cancel acts only on owner listings and never reaches another request of the host. + /// Request id the listing was started with. /// The to monitor for cancellation requests. The default is . - /// Outcome of writing user settings. - public async Task SetAsync(object settings, CancellationToken cancellationToken = default) + /// Whether the id named a running owner listing. + internal async Task CancelAsync(long requestId, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(settings); - - var request = new UserSettingsSetRequest { Settings = CopilotClient.ToJsonElementForWire(settings)!.Value }; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.set", [request], cancellationToken); + var request = new GitHubOwnersCancelRequest { RequestId = requestId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "gitHubOwners.cancel", [request], cancellationToken); } } -/// Provides server-scoped ManagedSettings APIs. +/// Provides server-scoped Git APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerManagedSettingsApi +public sealed class ServerGitApi { private readonly JsonRpc _rpc; - internal ServerManagedSettingsApi(JsonRpc rpc) + internal ServerGitApi(JsonRpc rpc) { _rpc = rpc; } - /// Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. - /// The to monitor for cancellation requests. The default is . - /// Validated device-managed settings discovered before a session exists. - public async Task ReadAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.read", [], cancellationToken); - } - - /// Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `<cacheHome>/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. + /// Reads the remote that the branch checked out in a working tree tracks, as `branch.<name>.remote` configures it. Reports `origin` rather than failing whenever there is no tracking configuration to read — on a detached HEAD, on a branch with no upstream, or when git itself fails — because a caller asking which remote to talk to needs an answer it can act on, not an error. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// Absolute path to a directory inside the git working tree to query. /// The to monitor for cancellation requests. The default is . - public async Task ClearCacheAsync(CancellationToken cancellationToken = default) + /// The remote the checked-out branch tracks. + internal async Task CurrentBranchRemoteAsync(string cwd, CancellationToken cancellationToken = default) { - await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.clearCache", [], cancellationToken); - } - - /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. - /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. - /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. - /// The to monitor for cancellation requests. The default is . - /// Effective enterprise managed settings for an account, resolved without a session. - public async Task ResolveAsync(string? selectionId = null, string? gitHubToken = null, string? clientName = null, CancellationToken cancellationToken = default) - { - var request = new ManagedSettingsResolveRequest { SelectionId = selectionId, GitHubToken = gitHubToken, ClientName = clientName }; - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolve", [request], cancellationToken); - } + ArgumentNullException.ThrowIfNull(cwd); - /// Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. - /// The to monitor for cancellation requests. The default is . - /// The authoring JSON schema for managed settings recognized by this runtime. - public async Task SchemaAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.schema", [], cancellationToken); + var request = new GitCwdRequest { Cwd = cwd }; + return await CopilotClient.InvokeRpcAsync(_rpc, "git.currentBranchRemote", [request], cancellationToken); } - /// Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. - /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. - /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. + /// Collects the repository context of a working directory in one call: working tree root, repository identifier and host, current branch, and the HEAD and base commits. Every repository field is omitted when the path is not inside a git working tree, and the requested path is echoed back as `cwd`. The answer is the same `SessionWorkingDirectoryContext` that `session.metadata.recordContextChange` accepts, so a caller polling for a context change can forward the result unchanged. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to derive session context from a directory itself. + /// Absolute path to a directory inside the git working tree to query. /// The to monitor for cancellation requests. The default is . - /// Result of validating a managed-settings document. - public async Task ValidateAsync(object content, string? layer = null, CancellationToken cancellationToken = default) + /// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. + internal async Task WorkingDirectoryContextAsync(string cwd, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(content); + ArgumentNullException.ThrowIfNull(cwd); - var request = new ManagedSettingsValidateRequest { Content = CopilotClient.ToJsonElementForWire(content)!.Value, Layer = layer }; - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.validate", [request], cancellationToken); + var request = new GitCwdRequest { Cwd = cwd }; + return await CopilotClient.InvokeRpcAsync(_rpc, "git.workingDirectoryContext", [request], cancellationToken); } - /// Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. - /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. + /// Lists the GitHub repositories a working tree's remotes point at, one entry per distinct repository, so a caller can resolve a base and head repository without parsing remote URLs itself. When several remotes name the same repository, only the first is listed, and the entry keeps that remote name. Remotes pointing at no GitHub host are left out, so an empty list means the tree reaches GitHub through no remote. Failing to read the remotes is reported as an error rather than as an empty list, because the two mean different things to a caller. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// Absolute path to the root of the git working tree. /// The to monitor for cancellation requests. The default is . - /// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. - public async Task ComposeAsync(IList layers, CancellationToken cancellationToken = default) + /// The GitHub repositories a working tree's remotes point at. + internal async Task ReposFromRemotesAsync(string gitRoot, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(layers); + ArgumentNullException.ThrowIfNull(gitRoot); - var request = new ManagedSettingsComposeRequest { Layers = layers }; - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.compose", [request], cancellationToken); + var request = new GitReposFromRemotesRequest { GitRoot = gitRoot }; + return await CopilotClient.InvokeRpcAsync(_rpc, "git.reposFromRemotes", [request], cancellationToken); } } @@ -43946,6 +50049,54 @@ public async Task EnrichMetadataAsync(IList(_rpc, "sessions.enrichMetadata", [request], cancellationToken); } + /// Creates the workspace record for a session that has not been opened yet. A host that hands a session off to another application — writing the record and then launching that application against the session ID — needs the record on disk before any session exists to carry it, which the session-scoped workspace methods cannot do. Replaces any existing record and resets the checkpoint index. When writing to the local filesystem, a stored `fork_count` survives on disk. Returns the record it built, so a surviving stored `fork_count` can differ from the answer. + /// Session ID the workspace record belongs to. + /// Directory the session's state is written under when no session filesystem provider is configured. Ignored when a provider is configured; the provider's session state path is used instead. + /// `windows` (any letter case) selects Windows path rules. Any other value selects POSIX path rules. + /// Starting working-directory context. The record keeps `cwd`, `gitRoot`, `repository`, `hostType`, `branch`, and `clientName`. Other fields, including `repositoryHost`, `headCommit`, and `baseCommit`, are ignored. `hostType` must be `github` or `ado`. + /// User-supplied display name for the workspace. + /// The to monitor for cancellation requests. The default is . + /// The workspace record that was written. + internal async Task CreateWorkspaceAsync(string sessionId, string sessionStatePath, string convention, SessionWorkingDirectoryContextWithClient? context = null, string? name = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(sessionId); + ArgumentNullException.ThrowIfNull(sessionStatePath); + ArgumentNullException.ThrowIfNull(convention); + + var request = new SessionsCreateWorkspaceRequest { SessionId = sessionId, SessionStatePath = sessionStatePath, Convention = convention, Context = context, Name = name }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sessions.createWorkspace", [request], cancellationToken); + } + + /// Reads a session's workspace record straight from disk, without opening the session. Resuming by session ID has to know where the session lives before it can connect, so the lookup cannot come from the session-scoped workspace methods, which resolve their location from a live session's context. Returns no record when the file is absent. + /// Root directory every session's state directory sits under. + /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. + /// The to monitor for cancellation requests. The default is . + /// The workspace record on disk, omitted when the session has none. + internal async Task LoadWorkspaceAsync(string sessionsHome, string sessionId, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(sessionsHome); + ArgumentNullException.ThrowIfNull(sessionId); + + var request = new SessionsLoadWorkspaceRequest { SessionsHome = sessionsHome, SessionId = sessionId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sessions.loadWorkspace", [request], cancellationToken); + } + + /// Merges fields into a session's workspace record on disk, creating the record when it is absent. The counterpart to `sessions.loadWorkspace`, for the same before-the-session-exists case. It preserves stored workspace-schema fields the request does not supply, does not preserve stored keys outside the workspace schema, and never replaces a stored `fork_count`. + /// Root directory every session's state directory sits under. + /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. + /// Workspace-schema fields to merge into the record, as a JSON object. Fields the object omits keep their stored values, except stored keys outside the schema are not preserved and a stored `fork_count` is never replaced. + /// The to monitor for cancellation requests. The default is . + /// The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. + internal async Task UpdateWorkspaceFieldsAsync(string sessionsHome, string sessionId, string fieldsJson, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(sessionsHome); + ArgumentNullException.ThrowIfNull(sessionId); + ArgumentNullException.ThrowIfNull(fieldsJson); + + var request = new SessionsUpdateWorkspaceFieldsRequest { SessionsHome = sessionsHome, SessionId = sessionId, FieldsJson = fieldsJson }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sessions.updateWorkspaceFields", [request], cancellationToken); + } + /// Reloads user, plugin, and (optionally) repo hooks on the active session. /// Active session ID to reload hooks for. /// When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. @@ -44092,6 +50243,58 @@ public async Task SpawnAsync(string cwd, string? agent } } +/// Provides server-scoped Connectors APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerConnectorsApi +{ + private readonly JsonRpc _rpc; + + internal ServerConnectorsApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Returns feature availability. + /// The to monitor for cancellation requests. The default is . + /// Feature availability. + public async Task GetCapabilitiesAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "connectors.getCapabilities", [], cancellationToken); + } + + /// Returns eligible accounts. + /// The to monitor for cancellation requests. The default is . + /// Eligible accounts. + public async Task GetAccountsAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "connectors.getAccounts", [], cancellationToken); + } + + /// Lists entries for the selected account. + /// Opaque account ID. + /// The to monitor for cancellation requests. The default is . + /// Entries for the selected account. + public async Task ListAsync(string accountId, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(accountId); + + var request = new ConnectorDiscoveryAccountRequest { AccountId = accountId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "connectors.list", [request], cancellationToken); + } + + /// Refreshes entries for the selected account. + /// Opaque account ID. + /// The to monitor for cancellation requests. The default is . + /// Entries for the selected account. + public async Task RefreshAsync(string accountId, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(accountId); + + var request = new ConnectorDiscoveryAccountRequest { AccountId = accountId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "connectors.refresh", [request], cancellationToken); + } +} + /// Provides typed session-scoped RPC methods. public sealed class SessionRpc { @@ -44356,6 +50559,12 @@ internal SessionRpc(CopilotSession session) Interlocked.CompareExchange(ref field, new(_session), null) ?? field; + /// Quota APIs. + public QuotaApi Quota => + field ?? + Interlocked.CompareExchange(ref field, new(_session), null) ?? + field; + /// LimitPrediction APIs. public LimitPredictionApi LimitPrediction => field ?? @@ -44645,6 +50854,17 @@ public async Task GetEnforcementStatusAsync(Cancellati return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.sandbox.getEnforcementStatus", [request], cancellationToken); } + /// Lists possible secret-bearing environment variables available to new sandboxed shells that are not already covered by credential masking. Uses local name rules and known-provider host suggestions, never returns secret values, and changes no settings or network permissions. Returns no suggestions while the session is not sandboxed. + /// The to monitor for cancellation requests. The default is . + /// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + public async Task GetCredentialSuggestionsAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionSandboxGetCredentialSuggestionsRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.sandbox.getCredentialSuggestions", [request], cancellationToken); + } + /// Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass. /// Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. /// Optional attribution for the permission decision. @@ -45061,14 +51281,13 @@ internal CanvasProviderApi(CopilotSession session) /// Provider metadata supplied by the host. /// Canvas contributions supplied by the provider. /// The to monitor for cancellation requests. The default is . - internal async Task RegisterAsync(string connectionId, object info, IList canvases, CancellationToken cancellationToken = default) + internal async Task RegisterAsync(string connectionId, object? info, IList canvases, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(connectionId); - ArgumentNullException.ThrowIfNull(info); ArgumentNullException.ThrowIfNull(canvases); _session.ThrowIfDisposed(); - var request = new CanvasProviderRegisterRequest { SessionId = _session.SessionId, ConnectionId = connectionId, Info = CopilotClient.ToJsonElementForWire(info)!.Value, Canvases = canvases.Select(static v => CopilotClient.ToJsonElementForWire(v)!.Value).ToList() }; + var request = new CanvasProviderRegisterRequest { SessionId = _session.SessionId, ConnectionId = connectionId, Info = CopilotClient.ToJsonElementForWire(info) ?? JsonElement.Parse("null"), Canvases = canvases.Select(static v => CopilotClient.ToJsonElementForWire(v)!.Value).ToList() }; await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.canvas.provider.register", [request], cancellationToken); } @@ -45102,13 +51321,12 @@ internal WorkflowApi(CopilotSession session) /// Workflow invocation options. /// The to monitor for cancellation requests. The default is . /// Complete current or terminal workflow run envelope. - public async Task RunAsync(string name, object args, WorkflowRunOptions? options = null, CancellationToken cancellationToken = default) + public async Task RunAsync(string name, object? args, WorkflowRunOptions? options = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(args); _session.ThrowIfDisposed(); - var request = new WorkflowRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args)!.Value, Options = options }; + var request = new WorkflowRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args) ?? JsonElement.Parse("null"), Options = options }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workflow.run", [request], cancellationToken); } @@ -45135,13 +51353,12 @@ public async Task ResumeAsync(string runId, WorkflowRunLim /// Opaque identifier of the originating tool call. /// The to monitor for cancellation requests. The default is . /// Complete current or terminal workflow run envelope. - internal async Task RunFromToolAsync(string name, object args, WorkflowToolRunOptions? options = null, string? toolCallId = null, CancellationToken cancellationToken = default) + internal async Task RunFromToolAsync(string name, object? args, WorkflowToolRunOptions? options = null, string? toolCallId = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(args); _session.ThrowIfDisposed(); - var request = new WorkflowToolRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args)!.Value, Options = options, ToolCallId = toolCallId }; + var request = new WorkflowToolRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args) ?? JsonElement.Parse("null"), Options = options, ToolCallId = toolCallId }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workflow.runFromTool", [request], cancellationToken); } @@ -45337,15 +51554,14 @@ public async Task GetAsync(string runId, string execut /// JSON result to memoize. /// The to monitor for cancellation requests. The default is . /// Acknowledgement that a workflow request was accepted. - public async Task PutAsync(string runId, string executionToken, string key, object resultJson, CancellationToken cancellationToken = default) + public async Task PutAsync(string runId, string executionToken, string key, object? resultJson, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(runId); ArgumentNullException.ThrowIfNull(executionToken); ArgumentNullException.ThrowIfNull(key); - ArgumentNullException.ThrowIfNull(resultJson); _session.ThrowIfDisposed(); - var request = new WorkflowJournalPutRequest { SessionId = _session.SessionId, RunId = runId, ExecutionToken = executionToken, Key = key, ResultJson = CopilotClient.ToJsonElementForWire(resultJson)!.Value }; + var request = new WorkflowJournalPutRequest { SessionId = _session.SessionId, RunId = runId, ExecutionToken = executionToken, Key = key, ResultJson = CopilotClient.ToJsonElementForWire(resultJson) ?? JsonElement.Parse("null") }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workflow.journal.put", [request], cancellationToken); } } @@ -45373,7 +51589,7 @@ public async Task GetCurrentAsync(CancellationToken cancellationTo } /// Switches the session to a model and optional reasoning configuration. - /// Model selection id to switch to, as returned by `list`. A bare id (e.g. `claude-sonnet-4.6`) names a Copilot (CAPI) model; a provider-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a registry BYOK model. + /// Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. /// Reasoning summary mode to request for supported model clients. @@ -45395,10 +51611,23 @@ public async Task SwitchToAsync(string modelId, AutoTier? a ArgumentNullException.ThrowIfNull(modelId); _session.ThrowIfDisposed(); - var request = new ModelSwitchToRequest { SessionId = _session.SessionId, ModelId = modelId, AutoTier = autoTier, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, Verbosity = verbosity, ModelCapabilities = modelCapabilities, ContextTier = contextTier, Source = source, DeferIfModelChangeQueued = deferIfModelChangeQueued, CompactionDecision = compactionDecision, RunCompactionPreflight = runCompactionPreflight, RepoScope = repoScope, ModelChangeScope = modelChangeScope, RequireAvailable = requireAvailable, PickerPersistence = pickerPersistence }; + var request = new ModelSwitchToRequestWithSession { SessionId = _session.SessionId, ModelId = modelId, AutoTier = autoTier, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, Verbosity = verbosity, ModelCapabilities = modelCapabilities, ContextTier = contextTier, Source = source, DeferIfModelChangeQueued = deferIfModelChangeQueued, CompactionDecision = compactionDecision, RunCompactionPreflight = runCompactionPreflight, RepoScope = repoScope, ModelChangeScope = modelChangeScope, RequireAvailable = requireAvailable, PickerPersistence = pickerPersistence }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.switchTo", [request], cancellationToken); } + /// Switches the session to a model and optional reasoning configuration. + /// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. + /// The to monitor for cancellation requests. The default is . + /// The model identifier active on the session after the switch. + public async Task SwitchToAsync(ModelSwitchToRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + ArgumentNullException.ThrowIfNull(request.ModelId); + _session.ThrowIfDisposed(); + var wireRequest = new ModelSwitchToRequestWithSession { SessionId = _session.SessionId, ModelId = request.ModelId, ProviderId = request.ProviderId, AutoTier = request.AutoTier, ReasoningEffort = request.ReasoningEffort, ReasoningSummary = request.ReasoningSummary, Verbosity = request.Verbosity, ModelCapabilities = request.ModelCapabilities, ContextTier = request.ContextTier, Source = request.Source, DeferIfModelChangeQueued = request.DeferIfModelChangeQueued, CompactionDecision = request.CompactionDecision, RunCompactionPreflight = request.RunCompactionPreflight, RepoScope = request.RepoScope, ModelChangeScope = request.ModelChangeScope, RequireAvailable = request.RequireAvailable, PickerPersistence = request.PickerPersistence }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.switchTo", [wireRequest], cancellationToken); + } + /// Requests an Auto preference change without changing the session's selected model. The latest unclaimed request wins; the runtime commits it only after a later prompt using the `auto` model mints a usable model and token pair. A `pending` response confirms that the request was accepted, not that it committed. Observe eventual success through `session.model_change`, failure through the ephemeral `session.auto_tier_switch_failed` event, or current unclaimed state through `session.model.getCurrent`. /// Auto preference to activate when a future user turn using the `auto` model safely mints a replacement model and token pair. Pass null to return to provider-default Auto routing. /// Origin to record on the effective `session.model_change` event. Defaults to `sdk` when omitted. @@ -45418,6 +51647,7 @@ public async Task SwitchAutoTierAsync(AutoTier? autoT /// Startup default model from the enterprise policy helper, when configured. Weakest of the managed sources: it applies only when neither device nor server policy names a model, and an explicit user selection still wins. /// Effective default Auto routing preference from user and managed settings. Applies only to fresh sessions and never replaces a per-session selection. /// Model selected by repository settings, when configured. + /// Provider owning the repository-selected model. Omitted repository provider identity retains legacy bare-model behavior. /// Reasoning effort selected by repository settings, when configured. /// Context tier selected by repository settings, when configured. /// Auto routing preference selected by repository settings, when configured. Applied only when the overlay selects the Auto model; beside a concrete model it stays dormant. @@ -45427,14 +51657,27 @@ public async Task SwitchAutoTierAsync(AutoTier? autoT /// Context tier paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. /// The to monitor for cancellation requests. The default is . /// The model identifier active on the session after the switch. - internal async Task ApplyStartupOverlayAsync(string? deviceManagedModel = null, string? serverManagedModel = null, string? policyHelperModel = null, AutoTier? autoTier = null, string? repoModel = null, string? repoReasoningEffort = null, string? repoContextTier = null, string? repoAutoTier = null, string? cliModel = null, bool? deferredResume = null, string? managedReasoningEffort = null, string? managedContextTier = null, CancellationToken cancellationToken = default) + internal async Task ApplyStartupOverlayAsync(string? deviceManagedModel = null, string? serverManagedModel = null, string? policyHelperModel = null, AutoTier? autoTier = null, string? repoModel = null, string? repoModelProviderId = null, string? repoReasoningEffort = null, string? repoContextTier = null, string? repoAutoTier = null, string? cliModel = null, bool? deferredResume = null, string? managedReasoningEffort = null, string? managedContextTier = null, CancellationToken cancellationToken = default) { _session.ThrowIfDisposed(); - var request = new ModelApplyStartupOverlayRequest { SessionId = _session.SessionId, DeviceManagedModel = deviceManagedModel, ServerManagedModel = serverManagedModel, PolicyHelperModel = policyHelperModel, AutoTier = autoTier, RepoModel = repoModel, RepoReasoningEffort = repoReasoningEffort, RepoContextTier = repoContextTier, RepoAutoTier = repoAutoTier, CliModel = cliModel, DeferredResume = deferredResume, ManagedReasoningEffort = managedReasoningEffort, ManagedContextTier = managedContextTier }; + var request = new ModelApplyStartupOverlayRequest { SessionId = _session.SessionId, DeviceManagedModel = deviceManagedModel, ServerManagedModel = serverManagedModel, PolicyHelperModel = policyHelperModel, AutoTier = autoTier, RepoModel = repoModel, RepoModelProviderId = repoModelProviderId, RepoReasoningEffort = repoReasoningEffort, RepoContextTier = repoContextTier, RepoAutoTier = repoAutoTier, CliModel = cliModel, DeferredResume = deferredResume, ManagedReasoningEffort = managedReasoningEffort, ManagedContextTier = managedContextTier }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.applyStartupOverlay", [request], cancellationToken); } + /// Clears an unchanged startup model/provider seed before default-model resolution. Never clears a resumed or user-selected model. + /// The expectedModel parameter. + /// Provider captured with the startup seed; omission matches only an unqualified seed. + /// The to monitor for cancellation requests. The default is . + internal async Task ClearStartupSeedAsync(string expectedModel, string? expectedProviderId = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(expectedModel); + _session.ThrowIfDisposed(); + + var request = new SessionModelClearStartupSeedRequest { SessionId = _session.SessionId, ExpectedModel = expectedModel, ExpectedProviderId = expectedProviderId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.clearStartupSeed", [request], cancellationToken); + } + /// Replaces or clears the host-supplied model allowlist for a running session. /// Exact model IDs to permit, or null to clear the host restriction. /// The to monitor for cancellation requests. The default is . @@ -45460,6 +51703,19 @@ public async Task SetReasoningEffortAsync(string return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.setReasoningEffort", [request], cancellationToken); } + /// Computes whether the session's current model shows reasoning summaries and how a host should present them: the default Ctrl+T visibility, reasoning headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is redundant. The runtime folds in the session's model catalog, selection and reasoning-summaries experiment assignment; the host supplies only its own persisted setting and current visibility. This method reads the session's resolved model catalog rather than resolving it, so call `session.model.list` first on a session that has not listed models or run a turn; until then the result is `ready: false`. A session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider, never caches one and stays `ready: false`. + /// The host's persisted `showReasoning` user setting, omitted when unset. + /// Whether the host is currently showing reasoning summaries. Defaults to false. + /// The to monitor for cancellation requests. The default is . + /// Reasoning-summaries presentation policy for the session's current model. + public async Task GetReasoningSummariesAsync(bool? persistedShowReasoning = null, bool? summariesVisible = null, CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new ModelGetReasoningSummariesRequest { SessionId = _session.SessionId, PersistedShowReasoning = persistedShowReasoning, SummariesVisible = summariesVisible }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.getReasoningSummaries", [request], cancellationToken); + } + /// Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's. /// Optional listing options. /// The to monitor for cancellation requests. The default is . @@ -45501,6 +51757,7 @@ public async Task GetAsync(CancellationToken cancellationToken = de /// Session whose plan-mode base state should be inherited. /// Whether a dedicated plan model is configured. /// Dedicated model to use in plan mode, when configured. + /// Provider owning planModel. Omit for legacy bare-model selection. /// Reasoning effort to use with the dedicated plan model. /// Context tier to use with the dedicated plan model. /// Explicit response to a model-switch compaction preflight. @@ -45510,11 +51767,11 @@ public async Task GetAsync(CancellationToken cancellationToken = de /// Action to perform when leaving plan mode. /// The to monitor for cancellation requests. The default is . /// Outcome of a session mode change, including any model switch it triggered and follow-up the host must perform. - public async Task SetAsync(SessionMode mode, SessionMode? expectedMode = null, string? inheritPlanBaseFromSessionId = null, bool? planModelConfigured = null, string? planModel = null, string? planReasoningEffort = null, string? planContextTier = null, string? compactionDecision = null, bool? restorePlanModel = null, bool? persistPlanSelection = null, ModelPickerSettingsContext? pickerSettingsContext = null, string? planExitAction = null, CancellationToken cancellationToken = default) + public async Task SetAsync(SessionMode mode, SessionMode? expectedMode = null, string? inheritPlanBaseFromSessionId = null, bool? planModelConfigured = null, string? planModel = null, string? planModelProviderId = null, string? planReasoningEffort = null, string? planContextTier = null, string? compactionDecision = null, bool? restorePlanModel = null, bool? persistPlanSelection = null, ModelPickerSettingsContext? pickerSettingsContext = null, string? planExitAction = null, CancellationToken cancellationToken = default) { _session.ThrowIfDisposed(); - var request = new ModeSetRequest { SessionId = _session.SessionId, Mode = mode, ExpectedMode = expectedMode, InheritPlanBaseFromSessionId = inheritPlanBaseFromSessionId, PlanModelConfigured = planModelConfigured, PlanModel = planModel, PlanReasoningEffort = planReasoningEffort, PlanContextTier = planContextTier, CompactionDecision = compactionDecision, RestorePlanModel = restorePlanModel, PersistPlanSelection = persistPlanSelection, PickerSettingsContext = pickerSettingsContext, PlanExitAction = planExitAction }; + var request = new ModeSetRequest { SessionId = _session.SessionId, Mode = mode, ExpectedMode = expectedMode, InheritPlanBaseFromSessionId = inheritPlanBaseFromSessionId, PlanModelConfigured = planModelConfigured, PlanModel = planModel, PlanModelProviderId = planModelProviderId, PlanReasoningEffort = planReasoningEffort, PlanContextTier = planContextTier, CompactionDecision = compactionDecision, RestorePlanModel = restorePlanModel, PersistPlanSelection = persistPlanSelection, PickerSettingsContext = pickerSettingsContext, PlanExitAction = planExitAction }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mode.set", [request], cancellationToken); } } @@ -45891,9 +52148,21 @@ public async Task DiffAsync(WorkspaceDiffMode mode, bool? i { _session.ThrowIfDisposed(); - var request = new WorkspacesDiffRequest { SessionId = _session.SessionId, Mode = mode, IgnoreWhitespace = ignoreWhitespace }; + var request = new WorkspacesDiffRequestWithSession { SessionId = _session.SessionId, Mode = mode, IgnoreWhitespace = ignoreWhitespace }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workspaces.diff", [request], cancellationToken); } + + /// Computes a diff for the session workspace. Never rejects for a busy session: a `session`-mode diff that cannot read the session's file-change captures falls back to an unstaged git diff with `isFallback: true` and reports why in `unavailableReason`. + /// Parameters for computing a workspace diff. + /// The to monitor for cancellation requests. The default is . + /// Workspace diff result for the requested mode. + public async Task DiffAsync(WorkspacesDiffRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + _session.ThrowIfDisposed(); + var wireRequest = new WorkspacesDiffRequestWithSession { SessionId = _session.SessionId, Mode = request.Mode, IgnoreWhitespace = request.IgnoreWhitespace, IncludeContents = request.IncludeContents }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workspaces.diff", [wireRequest], cancellationToken); + } } /// Provides session-scoped AutopilotObjective APIs. @@ -46402,7 +52671,18 @@ internal McpApi(CopilotSession session) _session = session; } - /// Lists MCP servers configured for the session, their connection status, and host-level state. The host-level state (disabled/filtered servers, failed/needs-auth/pending connections, mcp3p policy, full config) is empty/zero when no MCP host has been initialized for the session. + /// Records the IDE the host is connected to, so the agent's system prompt can name it and its workspace folder. Null or an omitted `ide` clears the recorded value, which is how a host reports that it is disconnected; there is no separate clear method. Both `ideName` and `workspaceFolder` are required together, because half a state cannot be attributed to a project. + /// The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports that it is disconnected. + /// The to monitor for cancellation requests. The default is . + internal async Task SetConnectedIdeInfoAsync(SessionConnectedIdeInfo? ide = null, CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionMcpSetConnectedIdeInfoParams { SessionId = _session.SessionId, Ide = ide }; + await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.setConnectedIdeInfo", [request], cancellationToken); + } + + /// Lists materialized MCP servers and their connection status. Cache misses may start and wait for MCP servers. /// The to monitor for cancellation requests. The default is . /// MCP servers configured for the session, with their connection status and host-level state. public async Task ListAsync(CancellationToken cancellationToken = default) @@ -46413,6 +52693,17 @@ public async Task ListAsync(CancellationToken cancellationToken = return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.list", [request], cancellationToken); } + /// Lists effective MCP configuration without starting, restarting, authenticating, or waiting for servers. An optional live observation is from an already materialized matching server; this is not a readiness guarantee. + /// The to monitor for cancellation requests. The default is . + /// Effective MCP configuration with optional live observations from matching already materialized servers. + public async Task ListConfiguredAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionMcpListConfiguredRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.listConfigured", [request], cancellationToken); + } + /// Lists the tools exposed by a connected MCP server on this session's host. This performs a live `tools/list` request. Tool UI metadata is returned independently of whether MCP Apps rendering is enabled for the session. /// Name of the connected MCP server whose tools to list. /// The to monitor for cancellation requests. The default is . @@ -46513,15 +52804,13 @@ internal async Task ReloadWithConfigAsync(CancellationTok /// 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. /// The to monitor for cancellation requests. The default is . /// Outcome of an MCP sampling execution: success result, failure error, or cancellation. - public async Task ExecuteSamplingAsync(string requestId, string serverName, object mcpRequestId, McpExecuteSamplingRequest request, CancellationToken cancellationToken = default) + public async Task ExecuteSamplingAsync(string requestId, string serverName, object? mcpRequestId, object? request, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(requestId); ArgumentNullException.ThrowIfNull(serverName); - ArgumentNullException.ThrowIfNull(mcpRequestId); - ArgumentNullException.ThrowIfNull(request); _session.ThrowIfDisposed(); - var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = CopilotClient.ToJsonElementForWire(mcpRequestId)!.Value, Request = request }; + var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = CopilotClient.ToJsonElementForWire(mcpRequestId) ?? JsonElement.Parse("null"), Request = CopilotClient.ToJsonElementForWire(request) ?? JsonElement.Parse("null") }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.executeSampling", [rpcRequest], cancellationToken); } @@ -47435,6 +53724,18 @@ public async Task ReloadAsync(SessionPluginsReloadRequest? request = null, Cance await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.plugins.reload", [rpcRequest], cancellationToken); } + /// Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + /// Plugins required by the session's managed settings to install or update again. + /// The to monitor for cancellation requests. The default is . + /// Per-plugin outcomes of retrying the plugins required by the session's managed settings. + public async Task RetryManagedAsync(SessionPluginsRetryManagedRequest? request = null, CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var rpcRequest = new SessionPluginsRetryManagedRequestWithSession { SessionId = _session.SessionId, Plugins = request?.Plugins }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.plugins.retryManaged", [rpcRequest], cancellationToken); + } + /// Marketplaces APIs. public PluginsMarketplacesApi Marketplaces => field ?? @@ -47620,7 +53921,10 @@ internal OptionsApi(CopilotSession session) /// Whether interactive shell sessions are logged. /// How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. - /// Additional directories to search for skills. + /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. /// Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. /// Skill IDs that should be excluded from this session. @@ -47647,19 +53951,19 @@ internal OptionsApi(CopilotSession session) /// Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. /// Whether to skip embedding retrieval pipeline initialization and execution. /// Organization-level custom instructions to inject into the system prompt. - /// Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. + /// Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. /// Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). /// Whether to enable cross-session store writes and reads. - /// Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + /// Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. /// Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. /// Optional session limits. Pass null to clear the session limits. /// 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, ModelCapabilitiesOverride? modelCapabilitiesOverrides = null, string? reasoningEffort = null, OptionsUpdateReasoningSummary? reasoningSummary = null, Verbosity? verbosity = null, string? clientName = null, string? lspClientName = null, string? integrationId = null, IDictionary? featureFlags = null, bool? isExperimentalMode = null, ProviderConfig? provider = null, CapiSessionOptions? capi = null, string? workingDirectory = null, IList? availableTools = null, IList? excludedTools = null, IList? includedBuiltinAgents = null, IList? excludedBuiltinAgents = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, bool? enableScriptSafety = null, ShellOptions? shell = null, string? shellInitProfile = null, IList? shellProcessFlags = null, SandboxConfig? sandboxConfig = null, SandboxConfigSource? sandboxConfigSource = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, bool? allowAllMcpServerInstructions = null, IList? skillDirectories = null, IList? ignoredSkillsLocations = null, IList? includedBuiltinSkills = null, IList? disabledSkills = null, bool? enableOnDemandInstructionDiscovery = null, long? maxInlineBinaryBytes = null, IList? installedPlugins = null, bool? customAgentsLocalOnly = null, bool? suppressCustomAgentPrompt = 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, bool? eventsLogIncludesSubagents = null, IList? additionalContentExclusionPolicies = null, bool? manageScheduleEnabled = null, IList? sessionCapabilities = null, bool? skipEmbeddingRetrieval = null, string? organizationCustomInstructions = null, bool? enableFileHooks = null, bool? enableHostGitOperations = null, bool? enableSessionStore = null, bool? enableSkills = null, OptionsUpdateContextTier? contextTier = null, SessionLimitsConfig? sessionLimits = null, CancellationToken cancellationToken = default) + public async Task UpdateAsync(string? model = null, ModelCapabilitiesOverride? modelCapabilitiesOverrides = null, string? reasoningEffort = null, OptionsUpdateReasoningSummary? reasoningSummary = null, Verbosity? verbosity = null, string? clientName = null, string? lspClientName = null, string? integrationId = null, IDictionary? featureFlags = null, bool? isExperimentalMode = null, ProviderConfig? provider = null, CapiSessionOptions? capi = null, string? workingDirectory = null, IList? availableTools = null, IList? excludedTools = null, IList? includedBuiltinAgents = null, IList? excludedBuiltinAgents = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, bool? enableScriptSafety = null, ShellOptions? shell = null, string? shellInitProfile = null, IList? shellProcessFlags = null, SandboxConfig? sandboxConfig = null, SandboxConfigSource? sandboxConfigSource = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, bool? allowAllMcpServerInstructions = null, IList? skillDirectories = null, IList? agentDirectories = null, IList? instructionDirectories = null, IList? hookDirectories = null, IList? ignoredSkillsLocations = null, IList? includedBuiltinSkills = null, IList? disabledSkills = null, bool? enableOnDemandInstructionDiscovery = null, long? maxInlineBinaryBytes = null, IList? installedPlugins = null, bool? customAgentsLocalOnly = null, bool? suppressCustomAgentPrompt = 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, bool? eventsLogIncludesSubagents = null, IList? additionalContentExclusionPolicies = null, bool? manageScheduleEnabled = null, IList? sessionCapabilities = null, bool? skipEmbeddingRetrieval = null, string? organizationCustomInstructions = null, bool? enableFileHooks = null, bool? enableHostGitOperations = null, bool? enableSessionStore = null, bool? enableSkills = null, OptionsUpdateContextTier? contextTier = null, SessionLimitsConfig? sessionLimits = null, CancellationToken cancellationToken = default) { _session.ThrowIfDisposed(); - var request = new SessionUpdateOptionsParams { SessionId = _session.SessionId, Model = model, ModelCapabilitiesOverrides = modelCapabilitiesOverrides, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, Verbosity = verbosity, ClientName = clientName, LspClientName = lspClientName, IntegrationId = integrationId, FeatureFlags = featureFlags, IsExperimentalMode = isExperimentalMode, Provider = provider, Capi = capi, WorkingDirectory = workingDirectory, AvailableTools = availableTools, ExcludedTools = excludedTools, IncludedBuiltinAgents = includedBuiltinAgents, ExcludedBuiltinAgents = excludedBuiltinAgents, ToolFilterPrecedence = toolFilterPrecedence, EnableScriptSafety = enableScriptSafety, Shell = shell, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = sandboxConfig, SandboxConfigSource = sandboxConfigSource, LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, AllowAllMcpServerInstructions = allowAllMcpServerInstructions, SkillDirectories = skillDirectories, IgnoredSkillsLocations = ignoredSkillsLocations, IncludedBuiltinSkills = includedBuiltinSkills, DisabledSkills = disabledSkills, EnableOnDemandInstructionDiscovery = enableOnDemandInstructionDiscovery, MaxInlineBinaryBytes = maxInlineBinaryBytes, InstalledPlugins = installedPlugins, CustomAgentsLocalOnly = customAgentsLocalOnly, SuppressCustomAgentPrompt = suppressCustomAgentPrompt, SkipCustomInstructions = skipCustomInstructions, DisabledInstructionSources = disabledInstructionSources, CoauthorEnabled = coauthorEnabled, TrajectoryFile = trajectoryFile, EnableStreaming = enableStreaming, CopilotUrl = copilotUrl, AskUserDisabled = askUserDisabled, ContinueOnAutoMode = continueOnAutoMode, RunningInInteractiveMode = runningInInteractiveMode, EnableReasoningSummaries = enableReasoningSummaries, AgentContext = agentContext, EventsLogDirectory = eventsLogDirectory, EventsLogIncludesSubagents = eventsLogIncludesSubagents, AdditionalContentExclusionPolicies = additionalContentExclusionPolicies, ManageScheduleEnabled = manageScheduleEnabled, SessionCapabilities = sessionCapabilities, SkipEmbeddingRetrieval = skipEmbeddingRetrieval, OrganizationCustomInstructions = organizationCustomInstructions, EnableFileHooks = enableFileHooks, EnableHostGitOperations = enableHostGitOperations, EnableSessionStore = enableSessionStore, EnableSkills = enableSkills, ContextTier = contextTier, SessionLimits = sessionLimits }; + var request = new SessionUpdateOptionsParams { SessionId = _session.SessionId, Model = model, ModelCapabilitiesOverrides = modelCapabilitiesOverrides, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, Verbosity = verbosity, ClientName = clientName, LspClientName = lspClientName, IntegrationId = integrationId, FeatureFlags = featureFlags, IsExperimentalMode = isExperimentalMode, Provider = provider, Capi = capi, WorkingDirectory = workingDirectory, AvailableTools = availableTools, ExcludedTools = excludedTools, IncludedBuiltinAgents = includedBuiltinAgents, ExcludedBuiltinAgents = excludedBuiltinAgents, ToolFilterPrecedence = toolFilterPrecedence, EnableScriptSafety = enableScriptSafety, Shell = shell, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = sandboxConfig, SandboxConfigSource = sandboxConfigSource, LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, AllowAllMcpServerInstructions = allowAllMcpServerInstructions, SkillDirectories = skillDirectories, AgentDirectories = agentDirectories, InstructionDirectories = instructionDirectories, HookDirectories = hookDirectories, IgnoredSkillsLocations = ignoredSkillsLocations, IncludedBuiltinSkills = includedBuiltinSkills, DisabledSkills = disabledSkills, EnableOnDemandInstructionDiscovery = enableOnDemandInstructionDiscovery, MaxInlineBinaryBytes = maxInlineBinaryBytes, InstalledPlugins = installedPlugins, CustomAgentsLocalOnly = customAgentsLocalOnly, SuppressCustomAgentPrompt = suppressCustomAgentPrompt, SkipCustomInstructions = skipCustomInstructions, DisabledInstructionSources = disabledInstructionSources, CoauthorEnabled = coauthorEnabled, TrajectoryFile = trajectoryFile, EnableStreaming = enableStreaming, CopilotUrl = copilotUrl, AskUserDisabled = askUserDisabled, ContinueOnAutoMode = continueOnAutoMode, RunningInInteractiveMode = runningInInteractiveMode, EnableReasoningSummaries = enableReasoningSummaries, AgentContext = agentContext, EventsLogDirectory = eventsLogDirectory, EventsLogIncludesSubagents = eventsLogIncludesSubagents, AdditionalContentExclusionPolicies = additionalContentExclusionPolicies, ManageScheduleEnabled = manageScheduleEnabled, SessionCapabilities = sessionCapabilities, SkipEmbeddingRetrieval = skipEmbeddingRetrieval, OrganizationCustomInstructions = organizationCustomInstructions, EnableFileHooks = enableFileHooks, EnableHostGitOperations = enableHostGitOperations, EnableSessionStore = enableSessionStore, EnableSkills = enableSkills, ContextTier = contextTier, SessionLimits = sessionLimits }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.options.update", [request], cancellationToken); } } @@ -47711,7 +54015,7 @@ public async Task ListAsync(CancellationToken cancellationToken = return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.extensions.list", [request], cancellationToken); } - /// Enables an extension for the session. + /// Enables an extension for the session and persists the preference when the session has a settings store. Hosts synchronizing effective membership should use extensions.reconcile instead. /// Source-qualified extension ID to enable. /// The to monitor for cancellation requests. The default is . public async Task EnableAsync(string id, CancellationToken cancellationToken = default) @@ -47723,7 +54027,7 @@ public async Task EnableAsync(string id, CancellationToken cancellationToken = d await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.extensions.enable", [request], cancellationToken); } - /// Disables an extension for the session. + /// Disables an extension for the session and persists the preference when the session has a settings store. Hosts synchronizing effective membership should use extensions.reconcile instead. /// Source-qualified extension ID to disable. /// The to monitor for cancellation requests. The default is . public async Task DisableAsync(string id, CancellationToken cancellationToken = default) @@ -47745,6 +54049,17 @@ public async Task ReloadAsync(CancellationToken cancellationToken = default) await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.extensions.reload", [request], cancellationToken); } + /// Host-only reconciliation of authoritative session-effective extension membership and enablement. Refreshes runtime-owned discovery and preferences without persisting settings, installing plugins, or restarting unchanged activations. Returns ExtensionList only after required starts and process/contribution cleanup settle. Takes no caller inventory or overrides. Missing controllers, unready/incomplete discovery, unavailable workspaces, superseded inputs, and lifecycle failures are errors, not empty membership. Independently proven revocations may be applied before an error; retry converges without restarting healthy activations. Error data contains lifecycleChangesApplied and code: extension_reconciliation_host_required, extension_reconciliation_unavailable, extension_reconciliation_not_ready, extension_reconciliation_discovery_failed, extension_reconciliation_workspace_unavailable, extension_reconciliation_superseded, or extension_reconciliation_lifecycle_failed. Mark host reconciliation state applied only on success. On older runtimes, method-not-found must not fall back to global discovery and persistent extension disables. + /// The to monitor for cancellation requests. The default is . + /// Extensions discovered for the session, with their current status. + public async Task ReconcileAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionExtensionsReconcileRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.extensions.reconcile", [request], cancellationToken); + } + /// 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. /// Attachments to push into the next user-message turn. extension_context entries take the slim shape; standard variants take their full AttachmentSchema shape. /// 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. @@ -47776,13 +54091,12 @@ internal ToolsApi(CopilotSession session) /// Optional identifier used to correlate this invocation with its tool call. /// The to monitor for cancellation requests. The default is . /// Canonical result returned by a session tool. - public async Task ExecuteAsync(string name, object arguments, string? toolCallId = null, CancellationToken cancellationToken = default) + public async Task ExecuteAsync(string name, object? arguments, string? toolCallId = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(arguments); _session.ThrowIfDisposed(); - var request = new ToolsExecuteRequest { SessionId = _session.SessionId, Name = name, Arguments = CopilotClient.ToJsonElementForWire(arguments)!.Value, ToolCallId = toolCallId }; + var request = new ToolsExecuteRequest { SessionId = _session.SessionId, Name = name, Arguments = CopilotClient.ToJsonElementForWire(arguments) ?? JsonElement.Parse("null"), ToolCallId = toolCallId }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.tools.execute", [request], cancellationToken); } @@ -47809,13 +54123,12 @@ public async Task GetBuiltinDescriptorsAsync(b /// Final expanded result returned by the task_complete tool. /// The to monitor for cancellation requests. The default is . /// Task completion notification with summary from the agent. - public async Task TaskCompleteEventDataAsync(object toolArgs, ToolResultExpanded finalResult, CancellationToken cancellationToken = default) + public async Task TaskCompleteEventDataAsync(object? toolArgs, ToolResultExpanded finalResult, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(toolArgs); ArgumentNullException.ThrowIfNull(finalResult); _session.ThrowIfDisposed(); - var request = new ToolsTaskCompleteEventDataRequest { SessionId = _session.SessionId, ToolArgs = CopilotClient.ToJsonElementForWire(toolArgs)!.Value, FinalResult = finalResult }; + var request = new ToolsTaskCompleteEventDataRequest { SessionId = _session.SessionId, ToolArgs = CopilotClient.ToJsonElementForWire(toolArgs) ?? JsonElement.Parse("null"), FinalResult = finalResult }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.tools.taskCompleteEventData", [request], cancellationToken); } @@ -47834,6 +54147,17 @@ public async Task HandlePendingToolCallAsync(string return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.tools.handlePendingToolCall", [request], cancellationToken); } + /// Lists the external tool calls of the session and its sub-agents that are still waiting for session.tools.handlePendingToolCall. + /// The to monitor for cancellation requests. The default is . + /// External tool calls still waiting for a result. + public async Task ListPendingRequestsAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new ToolsListPendingRequestsRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.tools.listPendingRequests", [request], cancellationToken); + } + /// Resolves, builds, and validates the runtime tool list for the session. /// The to monitor for cancellation requests. The default is . /// Resolve, build, and validate the runtime tool list for this session. Subagent 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. @@ -47925,7 +54249,7 @@ public async Task InvokeAsync(string name, string? /// Whether the host applied or cancelled the pending invocation effect. /// The to monitor for cancellation requests. The default is . /// Whether finalizing the invocation effect succeeded, and the failure reason when it did not. - internal async Task FinalizeInvocationEffectAsync(CommandsFinalizeInvocationEffectRequestEffect effect, CommandsInvocationEffectOutcome outcome, CancellationToken cancellationToken = default) + internal async Task FinalizeInvocationEffectAsync(IDictionary effect, CommandsInvocationEffectOutcome outcome, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(effect); _session.ThrowIfDisposed(); @@ -48135,12 +54459,12 @@ internal async Task HandleHumanUserInputAsync(string requ /// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. /// The to monitor for cancellation requests. The default is . /// Indicates whether the pending UI request was resolved by this call. - public async Task HandlePendingSamplingAsync(string requestId, UIHandlePendingSamplingResponse? response = null, CancellationToken cancellationToken = default) + public async Task HandlePendingSamplingAsync(string requestId, object? response = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(requestId); _session.ThrowIfDisposed(); - var request = new UIHandlePendingSamplingRequest { SessionId = _session.SessionId, RequestId = requestId, Response = response }; + var request = new UIHandlePendingSamplingRequest { SessionId = _session.SessionId, RequestId = requestId, Response = CopilotClient.ToJsonElementForWire(response) }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.ui.handlePendingSampling", [request], cancellationToken); } @@ -48658,16 +54982,17 @@ public async Task ActivityAsync(CancellationToken cancellationT } /// Returns the token breakdown for the session's current context window for a given model. - /// Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default. - /// Maximum output tokens allowed by the target model. Pass 0 if unknown. + /// Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from the session. + /// Requested output allowance to reserve against the combined context ceiling. Pass 0 to resolve the session's request cap, falling back to the model's advertised output limit. /// Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. + /// Provider owning selectedModel. Omit to use the current provider for the current model, or deterministic legacy lookup for a different model. /// The to monitor for cancellation requests. The default is . /// Token breakdown for the session's current context window, or null if uninitialized. - public async Task ContextInfoAsync(long promptTokenLimit, long outputTokenLimit, string? selectedModel = null, CancellationToken cancellationToken = default) + public async Task ContextInfoAsync(long promptTokenLimit, long outputTokenLimit, string? selectedModel = null, string? providerId = null, CancellationToken cancellationToken = default) { _session.ThrowIfDisposed(); - var request = new MetadataContextInfoRequest { SessionId = _session.SessionId, PromptTokenLimit = promptTokenLimit, OutputTokenLimit = outputTokenLimit, SelectedModel = selectedModel }; + var request = new MetadataContextInfoRequest { SessionId = _session.SessionId, PromptTokenLimit = promptTokenLimit, OutputTokenLimit = outputTokenLimit, SelectedModel = selectedModel, ProviderId = providerId }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.metadata.contextInfo", [request], cancellationToken); } @@ -49221,12 +55546,11 @@ public async Task ClearAsync(CancellationToken cancellationToken = default) /// Opaque runtime-owned filter object. /// The to monitor for cancellation requests. The default is . /// Indicates whether a user-facing pending item was removed. - internal async Task ConsumeSystemNotificationsAsync(object filter, CancellationToken cancellationToken = default) + internal async Task ConsumeSystemNotificationsAsync(object? filter, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(filter); _session.ThrowIfDisposed(); - var request = new QueueConsumeSystemNotificationsRequest { SessionId = _session.SessionId, Filter = CopilotClient.ToJsonElementForWire(filter)!.Value }; + var request = new QueueConsumeSystemNotificationsRequest { SessionId = _session.SessionId, Filter = CopilotClient.ToJsonElementForWire(filter) ?? JsonElement.Parse("null") }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.queue.consumeSystemNotifications", [request], cancellationToken); } @@ -49341,6 +55665,64 @@ public async Task GetMetricsAsync(CancellationToken cance var request = new SessionUsageGetMetricsRequest { SessionId = _session.SessionId }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.usage.getMetrics", [request], cancellationToken); } + + /// Internal host-only replacement of absolute code-change totals reported by a relay host. + /// Absolute added-line total, replacing the previous reading. + /// Absolute removed-line total, replacing the previous reading. + /// Absolute changed-file count; omission preserves the previous count. + /// The to monitor for cancellation requests. The default is . + internal async Task SetCodeChangesAsync(double linesAdded, double linesRemoved, double? filesCount = null, CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionUsageSetCodeChangesRequest { SessionId = _session.SessionId, LinesAdded = linesAdded, LinesRemoved = linesRemoved, FilesCount = filesCount }; + await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.usage.setCodeChanges", [request], cancellationToken); + } +} + +/// Provides session-scoped Quota APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QuotaApi +{ + private readonly CopilotSession _session; + + internal QuotaApi(CopilotSession session) + { + _session = session; + } + + /// Gets the session's current quota and account projection without making a network request. + /// The to monitor for cancellation requests. The default is . + /// The incumbent session-owned quota and account projection. + public async Task GetAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionQuotaGetRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.quota.get", [request], cancellationToken); + } + + /// Refreshes the session's provider model catalog bypassing its cache, folds quota snapshots into session state, and returns the updated projection. Failures leave the last known quota intact. + /// The to monitor for cancellation requests. The default is . + /// The incumbent session-owned quota and account projection. + public async Task RefreshAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionQuotaRefreshRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.quota.refresh", [request], cancellationToken); + } + + /// Returns and clears the session's pending quota warnings. Reading or refreshing quota does not drain warnings. + /// The to monitor for cancellation requests. The default is . + /// Pending warnings returned and cleared by session.quota.takeWarnings. + public async Task> TakeWarningsAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionQuotaTakeWarningsRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync>(_session.Rpc, "session.quota.takeWarnings", [request], cancellationToken); + } } /// Provides session-scoped LimitPrediction APIs. @@ -50042,6 +56424,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.AgentInterruptedData), TypeInfoPropertyName = "SessionEventsAgentInterruptedData")] [JsonSerializable(typeof(GitHub.Copilot.AgentInterruptedEvent), TypeInfoPropertyName = "SessionEventsAgentInterruptedEvent")] [JsonSerializable(typeof(GitHub.Copilot.AgentModelPolicy), TypeInfoPropertyName = "SessionEventsAgentModelPolicy")] +[JsonSerializable(typeof(GitHub.Copilot.AiCreditsStatus), TypeInfoPropertyName = "SessionEventsAiCreditsStatus")] [JsonSerializable(typeof(GitHub.Copilot.AssistantFusionPhaseActivityEvent), TypeInfoPropertyName = "SessionEventsAssistantFusionPhaseActivityEvent")] [JsonSerializable(typeof(GitHub.Copilot.AssistantFusionPhaseCompletedEvent), TypeInfoPropertyName = "SessionEventsAssistantFusionPhaseCompletedEvent")] [JsonSerializable(typeof(GitHub.Copilot.AssistantFusionPhaseFailedEvent), TypeInfoPropertyName = "SessionEventsAssistantFusionPhaseFailedEvent")] @@ -50211,6 +56594,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.IndexedSearchIncrementalPhase), TypeInfoPropertyName = "SessionEventsIndexedSearchIncrementalPhase")] [JsonSerializable(typeof(GitHub.Copilot.IndexedSearchOutcome), TypeInfoPropertyName = "SessionEventsIndexedSearchOutcome")] [JsonSerializable(typeof(GitHub.Copilot.IndexedSearchState), TypeInfoPropertyName = "SessionEventsIndexedSearchState")] +[JsonSerializable(typeof(GitHub.Copilot.ManagedPermissionsContext), TypeInfoPropertyName = "SessionEventsManagedPermissionsContext")] +[JsonSerializable(typeof(GitHub.Copilot.ManagedPluginProgressPhase), TypeInfoPropertyName = "SessionEventsManagedPluginProgressPhase")] [JsonSerializable(typeof(GitHub.Copilot.ManagedSettingsEnforcedAction), TypeInfoPropertyName = "SessionEventsManagedSettingsEnforcedAction")] [JsonSerializable(typeof(GitHub.Copilot.ManagedSettingsEnforcedEscalation), TypeInfoPropertyName = "SessionEventsManagedSettingsEnforcedEscalation")] [JsonSerializable(typeof(GitHub.Copilot.ManagedSettingsResolvedSource), TypeInfoPropertyName = "SessionEventsManagedSettingsResolvedSource")] @@ -50255,10 +56640,15 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.ModelCallFinishedData), TypeInfoPropertyName = "SessionEventsModelCallFinishedData")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallFinishedEvent), TypeInfoPropertyName = "SessionEventsModelCallFinishedEvent")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallFinishedOutcome), TypeInfoPropertyName = "SessionEventsModelCallFinishedOutcome")] +[JsonSerializable(typeof(GitHub.Copilot.ModelCallRequestBodyEncoding), TypeInfoPropertyName = "SessionEventsModelCallRequestBodyEncoding")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallStartData), TypeInfoPropertyName = "SessionEventsModelCallStartData")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallStartEvent), TypeInfoPropertyName = "SessionEventsModelCallStartEvent")] +[JsonSerializable(typeof(GitHub.Copilot.ModelCallWebSocketFallbackErrorKind), TypeInfoPropertyName = "SessionEventsModelCallWebSocketFallbackErrorKind")] +[JsonSerializable(typeof(GitHub.Copilot.ModelCallWebSocketFallbackReason), TypeInfoPropertyName = "SessionEventsModelCallWebSocketFallbackReason")] [JsonSerializable(typeof(GitHub.Copilot.ModelChangeSource), TypeInfoPropertyName = "SessionEventsModelChangeSource")] [JsonSerializable(typeof(GitHub.Copilot.ModelDeselectedReason), TypeInfoPropertyName = "SessionEventsModelDeselectedReason")] +[JsonSerializable(typeof(GitHub.Copilot.ModelProviderKind), TypeInfoPropertyName = "SessionEventsModelProviderKind")] +[JsonSerializable(typeof(GitHub.Copilot.ModelProviderRef), TypeInfoPropertyName = "SessionEventsModelProviderRef")] [JsonSerializable(typeof(GitHub.Copilot.OmittedBinaryOmittedReason), TypeInfoPropertyName = "SessionEventsOmittedBinaryOmittedReason")] [JsonSerializable(typeof(GitHub.Copilot.OmittedBinaryResult), TypeInfoPropertyName = "SessionEventsOmittedBinaryResult")] [JsonSerializable(typeof(GitHub.Copilot.OmittedBinaryType), TypeInfoPropertyName = "SessionEventsOmittedBinaryType")] @@ -50332,12 +56722,25 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.PermissionRule), TypeInfoPropertyName = "SessionEventsPermissionRule")] [JsonSerializable(typeof(GitHub.Copilot.PermissionSandboxPathGrant), TypeInfoPropertyName = "SessionEventsPermissionSandboxPathGrant")] [JsonSerializable(typeof(GitHub.Copilot.PermissionSandboxPathGrantAccess), TypeInfoPropertyName = "SessionEventsPermissionSandboxPathGrantAccess")] +[JsonSerializable(typeof(GitHub.Copilot.PermissionWriteFileContent), TypeInfoPropertyName = "SessionEventsPermissionWriteFileContent")] +[JsonSerializable(typeof(GitHub.Copilot.PermissionWriteFileEdit), TypeInfoPropertyName = "SessionEventsPermissionWriteFileEdit")] [JsonSerializable(typeof(GitHub.Copilot.PersistedBinaryImage), TypeInfoPropertyName = "SessionEventsPersistedBinaryImage")] [JsonSerializable(typeof(GitHub.Copilot.PersistedBinaryImageType), TypeInfoPropertyName = "SessionEventsPersistedBinaryImageType")] [JsonSerializable(typeof(GitHub.Copilot.PersistedBinaryResult), TypeInfoPropertyName = "SessionEventsPersistedBinaryResult")] [JsonSerializable(typeof(GitHub.Copilot.PlanChangedOperation), TypeInfoPropertyName = "SessionEventsPlanChangedOperation")] [JsonSerializable(typeof(GitHub.Copilot.PromptCacheBreakData), TypeInfoPropertyName = "SessionEventsPromptCacheBreakData")] [JsonSerializable(typeof(GitHub.Copilot.PromptCacheBreakEvent), TypeInfoPropertyName = "SessionEventsPromptCacheBreakEvent")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderMonthlyUsage), TypeInfoPropertyName = "SessionEventsProviderMonthlyUsage")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderMonthlyUsageScope), TypeInfoPropertyName = "SessionEventsProviderMonthlyUsageScope")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderMonthlyUsageState), TypeInfoPropertyName = "SessionEventsProviderMonthlyUsageState")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaAccessState), TypeInfoPropertyName = "SessionEventsProviderQuotaAccessState")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaAcquisitionStatus), TypeInfoPropertyName = "SessionEventsProviderQuotaAcquisitionStatus")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaBudgetMetadata), TypeInfoPropertyName = "SessionEventsProviderQuotaBudgetMetadata")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaCapacityState), TypeInfoPropertyName = "SessionEventsProviderQuotaCapacityState")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaObservationKind), TypeInfoPropertyName = "SessionEventsProviderQuotaObservationKind")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaQuantityKind), TypeInfoPropertyName = "SessionEventsProviderQuotaQuantityKind")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaState), TypeInfoPropertyName = "SessionEventsProviderQuotaState")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaUnit), TypeInfoPropertyName = "SessionEventsProviderQuotaUnit")] [JsonSerializable(typeof(GitHub.Copilot.ReasoningSummary), TypeInfoPropertyName = "SessionEventsReasoningSummary")] [JsonSerializable(typeof(GitHub.Copilot.RecommendedAutoTier), TypeInfoPropertyName = "SessionEventsRecommendedAutoTier")] [JsonSerializable(typeof(GitHub.Copilot.RemediationAction), TypeInfoPropertyName = "SessionEventsRemediationAction")] @@ -50476,6 +56879,16 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.ToolUserRequestedData), TypeInfoPropertyName = "SessionEventsToolUserRequestedData")] [JsonSerializable(typeof(GitHub.Copilot.ToolUserRequestedEvent), TypeInfoPropertyName = "SessionEventsToolUserRequestedEvent")] [JsonSerializable(typeof(GitHub.Copilot.UIEphemeralQueryPhase), TypeInfoPropertyName = "SessionEventsUIEphemeralQueryPhase")] +[JsonSerializable(typeof(GitHub.Copilot.UsageAccountingIdentity), TypeInfoPropertyName = "SessionEventsUsageAccountingIdentity")] +[JsonSerializable(typeof(GitHub.Copilot.UsageGetMetricsResult), TypeInfoPropertyName = "SessionEventsUsageGetMetricsResult")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsAgentMetric), TypeInfoPropertyName = "SessionEventsUsageMetricsAgentMetric")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsCodeChanges), TypeInfoPropertyName = "SessionEventsUsageMetricsCodeChanges")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsModelMetric), TypeInfoPropertyName = "SessionEventsUsageMetricsModelMetric")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsModelMetricRequests), TypeInfoPropertyName = "SessionEventsUsageMetricsModelMetricRequests")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsModelMetricTokenDetail), TypeInfoPropertyName = "SessionEventsUsageMetricsModelMetricTokenDetail")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsModelMetricUsage), TypeInfoPropertyName = "SessionEventsUsageMetricsModelMetricUsage")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsProviderModelMetric), TypeInfoPropertyName = "SessionEventsUsageMetricsProviderModelMetric")] +[JsonSerializable(typeof(GitHub.Copilot.UsageMetricsTokenDetail), TypeInfoPropertyName = "SessionEventsUsageMetricsTokenDetail")] [JsonSerializable(typeof(GitHub.Copilot.UserInputCompletedData), TypeInfoPropertyName = "SessionEventsUserInputCompletedData")] [JsonSerializable(typeof(GitHub.Copilot.UserInputCompletedEvent), TypeInfoPropertyName = "SessionEventsUserInputCompletedEvent")] [JsonSerializable(typeof(GitHub.Copilot.UserInputRequestedData), TypeInfoPropertyName = "SessionEventsUserInputRequestedData")] @@ -50511,9 +56924,16 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(AbortRequest))] [JsonSerializable(typeof(AbortResult))] [JsonSerializable(typeof(AccountAllUsers))] +[JsonSerializable(typeof(AccountDescribeAuthInfoRequest))] +[JsonSerializable(typeof(AccountDescribeAuthInfoResult))] [JsonSerializable(typeof(AccountGetCurrentAuthResult))] +[JsonSerializable(typeof(AccountGetGistSupportRequest))] +[JsonSerializable(typeof(AccountGetGistSupportResult))] [JsonSerializable(typeof(AccountGetQuotaRequest))] [JsonSerializable(typeof(AccountGetQuotaResult))] +[JsonSerializable(typeof(AccountGetTokenEnvVarResult))] +[JsonSerializable(typeof(AccountGetWebUrlRequest))] +[JsonSerializable(typeof(AccountGetWebUrlResult))] [JsonSerializable(typeof(AccountLoginRequest))] [JsonSerializable(typeof(AccountLoginResult))] [JsonSerializable(typeof(AccountLogoutRequest))] @@ -50536,13 +56956,23 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(AgentSelectRequest))] [JsonSerializable(typeof(AgentSelectResult))] [JsonSerializable(typeof(AgentSetPromptRequest))] +[JsonSerializable(typeof(AgentsCustomAgentInitialModelDecisionParams))] +[JsonSerializable(typeof(AgentsCustomAgentInitialModelDecisionResult))] [JsonSerializable(typeof(AgentsDiscoverRequest))] +[JsonSerializable(typeof(AgentsGetAvailableBuiltinsRequest))] +[JsonSerializable(typeof(AgentsGetAvailableBuiltinsResult))] +[JsonSerializable(typeof(AgentsGetBuiltinDefinitionRequest))] +[JsonSerializable(typeof(AgentsGetBuiltinDefinitionResult))] +[JsonSerializable(typeof(AgentsGetBuiltinListingDefinitionRequest))] +[JsonSerializable(typeof(AgentsGetBuiltinListingDefinitionResult))] +[JsonSerializable(typeof(AgentsGetBuiltinsResult))] [JsonSerializable(typeof(AgentsGetDiscoveryPathsRequest))] [JsonSerializable(typeof(AuthEnumerateQuery))] [JsonSerializable(typeof(AuthEnumerateValue))] [JsonSerializable(typeof(AuthIdentity))] [JsonSerializable(typeof(AuthIdentityMetadata))] [JsonSerializable(typeof(AuthInfo))] +[JsonSerializable(typeof(AuthLoginAccount))] [JsonSerializable(typeof(AuthLoginAdvanceRequest))] [JsonSerializable(typeof(AuthLoginBeginRequest))] [JsonSerializable(typeof(AuthLoginBegun))] @@ -50555,11 +56985,15 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(AuthValidationError))] [JsonSerializable(typeof(AuthWrite))] [JsonSerializable(typeof(AuthWriteResult))] +[JsonSerializable(typeof(AutoTierDescriptor))] +[JsonSerializable(typeof(AutoTierMetadata))] +[JsonSerializable(typeof(AutoTierStatus))] [JsonSerializable(typeof(AutopilotObjectiveCreditLimit))] [JsonSerializable(typeof(AutopilotObjectiveGetStateResult))] [JsonSerializable(typeof(AutopilotObjectiveState))] [JsonSerializable(typeof(BuiltInModelCatalog))] [JsonSerializable(typeof(BuiltInModelCatalogEntry))] +[JsonSerializable(typeof(BuiltinAgentSummary))] [JsonSerializable(typeof(BuiltinToolDescriptor))] [JsonSerializable(typeof(BuiltinToolFormat))] [JsonSerializable(typeof(BuiltinToolInputSchema))] @@ -50602,7 +57036,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ClientTaskCancelResult))] [JsonSerializable(typeof(CommandList))] [JsonSerializable(typeof(CommandsFinalizeInvocationEffectRequest))] -[JsonSerializable(typeof(CommandsFinalizeInvocationEffectRequestEffect))] [JsonSerializable(typeof(CommandsFinalizeInvocationEffectResult))] [JsonSerializable(typeof(CommandsHandlePendingCommandRequest))] [JsonSerializable(typeof(CommandsHandlePendingCommandResult))] @@ -50628,6 +57061,13 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ConnectorConnectResult))] [JsonSerializable(typeof(ConnectorContinueRequest))] [JsonSerializable(typeof(ConnectorDisconnectResult))] +[JsonSerializable(typeof(ConnectorDiscoveryAccount))] +[JsonSerializable(typeof(ConnectorDiscoveryAccountList))] +[JsonSerializable(typeof(ConnectorDiscoveryAccountRequest))] +[JsonSerializable(typeof(ConnectorDiscoveryAuthInfo))] +[JsonSerializable(typeof(ConnectorDiscoveryCapabilities))] +[JsonSerializable(typeof(ConnectorDiscoveryCatalogEntry))] +[JsonSerializable(typeof(ConnectorDiscoveryCatalogResult))] [JsonSerializable(typeof(ConnectorReconcileRequest))] [JsonSerializable(typeof(ConnectorReconcileRequestWithSession))] [JsonSerializable(typeof(ConnectorRuntimeStatus))] @@ -50697,17 +57137,40 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ExternalToolTextResultForLlmBinaryResultsForLlm))] [JsonSerializable(typeof(ExternalToolTextResultForLlmContent))] [JsonSerializable(typeof(ExternalToolTextResultForLlmContentResourceLinkIcon))] +[JsonSerializable(typeof(FeatureFlagMetadata))] +[JsonSerializable(typeof(FeatureFlagsMetadataResult))] +[JsonSerializable(typeof(FeatureFlagsResolveRequest))] +[JsonSerializable(typeof(FeatureFlagsResolveStartupGatesRequest))] [JsonSerializable(typeof(FleetStartRequest))] [JsonSerializable(typeof(FleetStartResult))] [JsonSerializable(typeof(FolderTrustAddParams))] [JsonSerializable(typeof(FolderTrustCheckParams))] [JsonSerializable(typeof(FolderTrustCheckResult))] +[JsonSerializable(typeof(FolderTrustIsTrustedParams))] +[JsonSerializable(typeof(ForceLoginOrgsDecision))] +[JsonSerializable(typeof(GitCurrentBranchRemoteResult))] +[JsonSerializable(typeof(GitCwdRequest))] [JsonSerializable(typeof(GitHubEnvironment))] +[JsonSerializable(typeof(GitHubOwnerOption))] +[JsonSerializable(typeof(GitHubOwnersCancelRequest))] +[JsonSerializable(typeof(GitHubOwnersCancelResult))] +[JsonSerializable(typeof(GitHubOwnersListRequest))] +[JsonSerializable(typeof(GitHubOwnersListResult))] +[JsonSerializable(typeof(GitHubOwnersRequestIdResult))] +[JsonSerializable(typeof(GitHubRepositoryAtPathRequest))] +[JsonSerializable(typeof(GitHubRepositoryAtPathResult))] +[JsonSerializable(typeof(GitHubRepositoryIdentity))] [JsonSerializable(typeof(GitHubTelemetryClientInfo))] [JsonSerializable(typeof(GitHubTelemetryEvent))] [JsonSerializable(typeof(GitHubTelemetryNotification))] [JsonSerializable(typeof(GitHubTokenAcquireRequest))] [JsonSerializable(typeof(GitHubTokenAcquireResult))] +[JsonSerializable(typeof(GitRemoteRepository))] +[JsonSerializable(typeof(GitReposFromRemotesRequest))] +[JsonSerializable(typeof(GitReposFromRemotesResult))] +[JsonSerializable(typeof(GlobalStateLoadForConfigDirRequest))] +[JsonSerializable(typeof(GlobalStateLoadResult))] +[JsonSerializable(typeof(GlobalStateWriteKeyRequest))] [JsonSerializable(typeof(HandlePendingToolCallRequest))] [JsonSerializable(typeof(HandlePendingToolCallResult))] [JsonSerializable(typeof(HistoryAbortManualCompactionResult))] @@ -50737,6 +57200,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(HostGetConfigurationResult))] [JsonSerializable(typeof(HostGetEnvironmentCredentialsResult))] [JsonSerializable(typeof(HostGitHubEnvironmentOptions))] +[JsonSerializable(typeof(HostListSessionsRequest))] +[JsonSerializable(typeof(HostListSessionsResult))] [JsonSerializable(typeof(HostLocalServerConfiguration))] [JsonSerializable(typeof(HostLocalServerOptions))] [JsonSerializable(typeof(HostPublishSessionRequest))] @@ -50745,12 +57210,15 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(HostReadyResult))] [JsonSerializable(typeof(HostReleaseSessionRequest))] [JsonSerializable(typeof(HostReleaseSessionResult))] +[JsonSerializable(typeof(HostSessionSummary))] [JsonSerializable(typeof(HostStartRequest))] [JsonSerializable(typeof(HostStartResult))] [JsonSerializable(typeof(IDictionary))] +[JsonSerializable(typeof(IDictionary))] [JsonSerializable(typeof(IDictionary))] [JsonSerializable(typeof(IList))] [JsonSerializable(typeof(IList))] +[JsonSerializable(typeof(IList))] [JsonSerializable(typeof(IList))] [JsonSerializable(typeof(IList))] [JsonSerializable(typeof(InstallationCatalogueIdentity))] @@ -50762,9 +57230,11 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(InstructionDiscoveryPath))] [JsonSerializable(typeof(InstructionDiscoveryPathList))] [JsonSerializable(typeof(InstructionSource))] +[JsonSerializable(typeof(InstructionsDiscoverRepoSourcesRequest))] [JsonSerializable(typeof(InstructionsDiscoverRequest))] [JsonSerializable(typeof(InstructionsGetDiscoveryPathsRequest))] [JsonSerializable(typeof(InstructionsGetSourcesResult))] +[JsonSerializable(typeof(InstructionsInitPromptResult))] [JsonSerializable(typeof(InterruptMainTurnRequest))] [JsonSerializable(typeof(InterruptMainTurnResult))] [JsonSerializable(typeof(JsonSchemaResponseFormat))] @@ -50779,20 +57249,45 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(LlmInferenceHttpResponseStartResult))] [JsonSerializable(typeof(LlmInferenceSetProviderResult))] [JsonSerializable(typeof(LocalSessionMetadataValue))] +[JsonSerializable(typeof(LocationPermissionsCleanupResult))] [JsonSerializable(typeof(LogRequest))] [JsonSerializable(typeof(LogResult))] +[JsonSerializable(typeof(LoggedInUser))] [JsonSerializable(typeof(LspInitializeRequest))] +[JsonSerializable(typeof(ManagedPermissionEvaluation))] +[JsonSerializable(typeof(ManagedPermissionOperation))] +[JsonSerializable(typeof(ManagedPluginRetryEntry))] [JsonSerializable(typeof(ManagedSettingMeta))] +[JsonSerializable(typeof(ManagedSettingsApplyControlsParams))] +[JsonSerializable(typeof(ManagedSettingsApplyControlsResult))] [JsonSerializable(typeof(ManagedSettingsComposeLayer))] [JsonSerializable(typeof(ManagedSettingsComposeRequest))] [JsonSerializable(typeof(ManagedSettingsComposeResult))] [JsonSerializable(typeof(ManagedSettingsDiagnostic))] +[JsonSerializable(typeof(ManagedSettingsIngestParams))] +[JsonSerializable(typeof(ManagedSettingsIngestResult))] [JsonSerializable(typeof(ManagedSettingsLayer))] +[JsonSerializable(typeof(ManagedSettingsLoadRemoteControlParams))] +[JsonSerializable(typeof(ManagedSettingsLoadRemoteControlResult))] +[JsonSerializable(typeof(ManagedSettingsLogMessage))] [JsonSerializable(typeof(ManagedSettingsMeta))] +[JsonSerializable(typeof(ManagedSettingsParseClientValueParams))] +[JsonSerializable(typeof(ManagedSettingsParseClientValueResult))] +[JsonSerializable(typeof(ManagedSettingsPermissionsEvaluateRequest))] +[JsonSerializable(typeof(ManagedSettingsPermissionsEvaluateResult))] +[JsonSerializable(typeof(ManagedSettingsReadDeviceResult))] [JsonSerializable(typeof(ManagedSettingsReadResult))] +[JsonSerializable(typeof(ManagedSettingsResolveBypassDisableTransitionParams))] +[JsonSerializable(typeof(ManagedSettingsResolveBypassDisableTransitionResult))] +[JsonSerializable(typeof(ManagedSettingsResolveDeviceForceLoginOrgsGateParams))] +[JsonSerializable(typeof(ManagedSettingsResolveEffectiveValueParams))] +[JsonSerializable(typeof(ManagedSettingsResolveEffectiveValueResult))] [JsonSerializable(typeof(ManagedSettingsResolveRequest))] [JsonSerializable(typeof(ManagedSettingsResolveResult))] +[JsonSerializable(typeof(ManagedSettingsResolveStartupPolicyParams))] +[JsonSerializable(typeof(ManagedSettingsResolveStartupPolicyResult))] [JsonSerializable(typeof(ManagedSettingsResolvedData))] +[JsonSerializable(typeof(ManagedSettingsRetainPolicyParams))] [JsonSerializable(typeof(ManagedSettingsSchemaResult))] [JsonSerializable(typeof(ManagedSettingsValidateRequest))] [JsonSerializable(typeof(ManagedSettingsValidateResult))] @@ -50832,6 +57327,9 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpConfigUpdateRequest))] [JsonSerializable(typeof(McpConfigureGitHubRequest))] [JsonSerializable(typeof(McpConfigureGitHubResult))] +[JsonSerializable(typeof(McpConfiguredServer))] +[JsonSerializable(typeof(McpConfiguredServerList))] +[JsonSerializable(typeof(McpConfiguredServerState))] [JsonSerializable(typeof(McpDiagnosticDetails))] [JsonSerializable(typeof(McpDiagnosticSourceConfiguration))] [JsonSerializable(typeof(McpDisableRequest))] @@ -50841,8 +57339,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpEnableRequest))] [JsonSerializable(typeof(McpEnableRequestWithSession))] [JsonSerializable(typeof(McpExecuteSamplingParams))] -[JsonSerializable(typeof(McpExecuteSamplingRequest))] -[JsonSerializable(typeof(McpExecuteSamplingResult))] [JsonSerializable(typeof(McpFailedServer))] [JsonSerializable(typeof(McpFilteredServer))] [JsonSerializable(typeof(McpHeadersHandlePendingHeadersRefreshRequest))] @@ -50864,6 +57360,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpInstallationsRequest))] [JsonSerializable(typeof(McpIsServerRunningRequest))] [JsonSerializable(typeof(McpIsServerRunningResult))] +[JsonSerializable(typeof(McpListBuiltinServerNamesResult))] [JsonSerializable(typeof(McpListToolsRequest))] [JsonSerializable(typeof(McpListToolsResult))] [JsonSerializable(typeof(McpOauthAuthenticationStateChangedRequest))] @@ -50902,6 +57399,11 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpPromptsListRequest))] [JsonSerializable(typeof(McpPromptsListResult))] [JsonSerializable(typeof(McpRegisterExternalClientRequest))] +[JsonSerializable(typeof(McpRegistryCancelRequest))] +[JsonSerializable(typeof(McpRegistryCancelResult))] +[JsonSerializable(typeof(McpRegistryRequestIdResult))] +[JsonSerializable(typeof(McpRegistrySearchRequest))] +[JsonSerializable(typeof(McpRegistrySearchResult))] [JsonSerializable(typeof(McpReloadWithConfigRequest))] [JsonSerializable(typeof(McpRemoveGitHubResult))] [JsonSerializable(typeof(McpResource))] @@ -50926,6 +57428,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpServerOwnership))] [JsonSerializable(typeof(McpSetEnvValueModeParams))] [JsonSerializable(typeof(McpSetEnvValueModeResult))] +[JsonSerializable(typeof(McpShouldExcludeGitHubToolsRequest))] +[JsonSerializable(typeof(McpShouldExcludeGitHubToolsResult))] [JsonSerializable(typeof(McpSourceFile))] [JsonSerializable(typeof(McpSourcePlugin))] [JsonSerializable(typeof(McpSourceRef))] @@ -50976,11 +57480,12 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ModelCapabilitiesOverrideLimitsVision))] [JsonSerializable(typeof(ModelCapabilitiesOverrideSupports))] [JsonSerializable(typeof(ModelCapabilitiesSupports))] +[JsonSerializable(typeof(ModelGetReasoningSummariesRequest))] +[JsonSerializable(typeof(ModelGetReasoningSummariesResult))] [JsonSerializable(typeof(ModelList))] [JsonSerializable(typeof(ModelMessage))] [JsonSerializable(typeof(ModelPickerPersistenceRequest))] [JsonSerializable(typeof(ModelPickerSettingsContext))] -[JsonSerializable(typeof(ModelPickerSettingsContextEnvironment))] [JsonSerializable(typeof(ModelPolicy))] [JsonSerializable(typeof(ModelProviderAdapterCatalog))] [JsonSerializable(typeof(ModelProviderAdapterDescriptor))] @@ -50998,7 +57503,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ModelProviderOperationOutcome))] [JsonSerializable(typeof(ModelProviderPrepareConfigurationRequest))] [JsonSerializable(typeof(ModelProviderProvenance))] -[JsonSerializable(typeof(ModelProviderRef))] [JsonSerializable(typeof(ModelProviderStatus))] [JsonSerializable(typeof(ModelProviderWarning))] [JsonSerializable(typeof(ModelSetAllowedModelsRequest))] @@ -51009,6 +57513,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ModelSwitchAutoTierResult))] [JsonSerializable(typeof(ModelSwitchConfirmation))] [JsonSerializable(typeof(ModelSwitchToRequest))] +[JsonSerializable(typeof(ModelSwitchToRequestWithSession))] [JsonSerializable(typeof(ModelSwitchToResult))] [JsonSerializable(typeof(ModelWarningText))] [JsonSerializable(typeof(ModelsListRequest))] @@ -51022,6 +57527,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(OptionsUpdateAdditionalContentExclusionPolicy))] [JsonSerializable(typeof(OptionsUpdateAdditionalContentExclusionPolicyRule))] [JsonSerializable(typeof(OptionsUpdateAdditionalContentExclusionPolicyRuleSource))] +[JsonSerializable(typeof(PendingExternalToolRequest))] +[JsonSerializable(typeof(PendingExternalToolRequestList))] [JsonSerializable(typeof(PendingPermissionRequest))] [JsonSerializable(typeof(PendingPermissionRequestList))] [JsonSerializable(typeof(PermissionDecision))] @@ -51052,6 +57559,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(PermissionsConfigureAdditionalContentExclusionPolicyRuleSource))] [JsonSerializable(typeof(PermissionsConfigureParams))] [JsonSerializable(typeof(PermissionsConfigureResult))] +[JsonSerializable(typeof(PermissionsEvaluateManagedPolicyParams))] +[JsonSerializable(typeof(PermissionsEvaluateManagedPolicyResult))] [JsonSerializable(typeof(PermissionsFolderTrustAddTrustedResult))] [JsonSerializable(typeof(PermissionsGetModeRequest))] [JsonSerializable(typeof(PermissionsGetModeResult))] @@ -51073,6 +57582,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(PermissionsSetRequiredRequest))] [JsonSerializable(typeof(PermissionsSetRequiredResult))] [JsonSerializable(typeof(PermissionsUrlsSetUnrestrictedModeResult))] +[JsonSerializable(typeof(PersistenceWriteRawJsonLockedRequest))] +[JsonSerializable(typeof(PersistenceWriteRawJsonLockedResult))] [JsonSerializable(typeof(PingRequest))] [JsonSerializable(typeof(PingResult))] [JsonSerializable(typeof(PlanReadResult))] @@ -51163,6 +57674,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(QueueWithdrawMessageRequest))] [JsonSerializable(typeof(QueueWithdrawMessageResult))] [JsonSerializable(typeof(QueuedCommandResult))] +[JsonSerializable(typeof(QuotaWarningProjection))] [JsonSerializable(typeof(RegisterEventInterestParams))] [JsonSerializable(typeof(RegisterEventInterestResult))] [JsonSerializable(typeof(ReleaseEventInterestParams))] @@ -51179,7 +57691,13 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(RemoteSessionConnectionResult))] [JsonSerializable(typeof(RemoteSessionMetadataRepository))] [JsonSerializable(typeof(RemoteSessionMetadataValue))] +[JsonSerializable(typeof(RepoSettingsEditRequest))] +[JsonSerializable(typeof(RepoSettingsReadRawRequest))] +[JsonSerializable(typeof(RepoSettingsReadRawResult))] +[JsonSerializable(typeof(RepoSettingsWriteAllRequest))] +[JsonSerializable(typeof(RepoSettingsWriteKeyRequest))] [JsonSerializable(typeof(ResponseFormat))] +[JsonSerializable(typeof(SandboxApplyDefaultsRequest))] [JsonSerializable(typeof(SandboxConfig))] [JsonSerializable(typeof(SandboxConfigAuth))] [JsonSerializable(typeof(SandboxConfigUserPolicy))] @@ -51189,18 +57707,37 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SandboxConfigUserPolicyNetwork))] [JsonSerializable(typeof(SandboxConfigUserPolicyNetworkProxy))] [JsonSerializable(typeof(SandboxConfigUserPolicySeatbelt))] +[JsonSerializable(typeof(SandboxCredentialSuggestion))] +[JsonSerializable(typeof(SandboxCredentialSuggestionsResult))] [JsonSerializable(typeof(SandboxCredentialsConfig))] [JsonSerializable(typeof(SandboxDisableForSessionRequest))] [JsonSerializable(typeof(SandboxDisableForSessionResult))] +[JsonSerializable(typeof(SandboxDocsUrlResult))] +[JsonSerializable(typeof(SandboxEffectiveForOptionalParams))] +[JsonSerializable(typeof(SandboxEffectiveForOptionalResult))] +[JsonSerializable(typeof(SandboxEnforcementCommandAllowedParams))] [JsonSerializable(typeof(SandboxEnforcementStatus))] +[JsonSerializable(typeof(SandboxFilterPickerCandidatesParams))] +[JsonSerializable(typeof(SandboxFilterPickerCandidatesResult))] [JsonSerializable(typeof(SandboxGrantPathForRequestRequest))] [JsonSerializable(typeof(SandboxGrantPathForRequestResult))] [JsonSerializable(typeof(SandboxHostCapability))] [JsonSerializable(typeof(SandboxHostSupport))] [JsonSerializable(typeof(SandboxMaskedEnvVar))] +[JsonSerializable(typeof(SandboxPickerCandidate))] +[JsonSerializable(typeof(SandboxPreparePickerPolicyParams))] +[JsonSerializable(typeof(SandboxPreparePickerPolicyResult))] [JsonSerializable(typeof(SandboxProxyCaCreateResult))] [JsonSerializable(typeof(SandboxProxyCaRequest))] [JsonSerializable(typeof(SandboxProxyCaStatus))] +[JsonSerializable(typeof(SandboxProxySecretGetResult))] +[JsonSerializable(typeof(SandboxProxySecretLocation))] +[JsonSerializable(typeof(SandboxProxySecretSaveRequest))] +[JsonSerializable(typeof(SandboxProxySecretSaveResult))] +[JsonSerializable(typeof(SandboxResolveFlooredConfigParams))] +[JsonSerializable(typeof(SandboxResolveFlooredConfigResult))] +[JsonSerializable(typeof(SandboxUnsupportedStartupNoticeParams))] +[JsonSerializable(typeof(SandboxUnsupportedStartupNoticeResult))] [JsonSerializable(typeof(ScheduleAddAtRequest))] [JsonSerializable(typeof(ScheduleAddCronRequest))] [JsonSerializable(typeof(ScheduleAddRequest))] @@ -51244,6 +57781,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionCommandsListRequestWithSession))] [JsonSerializable(typeof(SessionCompletionItem))] [JsonSerializable(typeof(SessionCompletionsGetTriggerCharactersRequest))] +[JsonSerializable(typeof(SessionConnectedIdeInfo))] [JsonSerializable(typeof(SessionConnectorsGetAccountRequest))] [JsonSerializable(typeof(SessionConnectorsGetCapabilitiesRequest))] [JsonSerializable(typeof(SessionConnectorsGetStatusRequest))] @@ -51253,6 +57791,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionEnrichMetadataResult))] [JsonSerializable(typeof(SessionEventLogTailRequest))] [JsonSerializable(typeof(SessionExtensionsListRequest))] +[JsonSerializable(typeof(SessionExtensionsReconcileRequest))] [JsonSerializable(typeof(SessionExtensionsReloadRequest))] [JsonSerializable(typeof(SessionFsAppendFileRequest))] [JsonSerializable(typeof(SessionFsError))] @@ -51312,6 +57851,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionLoadDeferredRepoHooksResult))] [JsonSerializable(typeof(SessionManagedSettingsGetRequest))] [JsonSerializable(typeof(SessionMcpAppsGetHostContextRequest))] +[JsonSerializable(typeof(SessionMcpListConfiguredRequest))] [JsonSerializable(typeof(SessionMcpListRequest))] [JsonSerializable(typeof(SessionMcpMoveLoadingToBackgroundRequest))] [JsonSerializable(typeof(SessionMcpOauthCancelLoginRequest))] @@ -51320,6 +57860,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionMcpOauthPrepareLoginResult))] [JsonSerializable(typeof(SessionMcpReloadRequest))] [JsonSerializable(typeof(SessionMcpRemoveGitHubRequest))] +[JsonSerializable(typeof(SessionMcpSetConnectedIdeInfoParams))] [JsonSerializable(typeof(SessionMetadataActivityRequest))] [JsonSerializable(typeof(SessionMetadataGetClientMetadataRequest))] [JsonSerializable(typeof(SessionMetadataGetContextAttributionRequest))] @@ -51328,6 +57869,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionMetadataSnapshotRequest))] [JsonSerializable(typeof(SessionMetadataSnapshotWorkspace))] [JsonSerializable(typeof(SessionModeGetRequest))] +[JsonSerializable(typeof(SessionModelClearStartupSeedRequest))] +[JsonSerializable(typeof(SessionModelClearStartupSeedResult))] [JsonSerializable(typeof(SessionModelGetCurrentRequest))] [JsonSerializable(typeof(SessionModelList))] [JsonSerializable(typeof(SessionModelListRequest))] @@ -51348,6 +57891,9 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionPluginsMarketplacesRefreshRequestWithSession))] [JsonSerializable(typeof(SessionPluginsReloadRequest))] [JsonSerializable(typeof(SessionPluginsReloadRequestWithSession))] +[JsonSerializable(typeof(SessionPluginsRetryManagedRequest))] +[JsonSerializable(typeof(SessionPluginsRetryManagedRequestWithSession))] +[JsonSerializable(typeof(SessionPluginsRetryManagedResult))] [JsonSerializable(typeof(SessionProviderGetEndpointRequest))] [JsonSerializable(typeof(SessionProviderGetEndpointRequestWithSession))] [JsonSerializable(typeof(SessionProvidersGetCatalogRequest))] @@ -51359,7 +57905,15 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionQueueProcessRequest))] [JsonSerializable(typeof(SessionQueueRemoveMostRecentRequest))] [JsonSerializable(typeof(SessionQueueSnapshotRequest))] +[JsonSerializable(typeof(SessionQuotaDelegateWarning))] +[JsonSerializable(typeof(SessionQuotaGetRequest))] +[JsonSerializable(typeof(SessionQuotaGetResult))] +[JsonSerializable(typeof(SessionQuotaRefreshRequest))] +[JsonSerializable(typeof(SessionQuotaRefreshResult))] +[JsonSerializable(typeof(SessionQuotaSnapshot))] +[JsonSerializable(typeof(SessionQuotaTakeWarningsRequest))] [JsonSerializable(typeof(SessionRemoteDisableRequest))] +[JsonSerializable(typeof(SessionSandboxGetCredentialSuggestionsRequest))] [JsonSerializable(typeof(SessionSandboxGetEnforcementStatusRequest))] [JsonSerializable(typeof(SessionScheduleHasSelfPacedRequest))] [JsonSerializable(typeof(SessionScheduleHydrateRequest))] @@ -51395,9 +57949,11 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionUpdateOptionsParams))] [JsonSerializable(typeof(SessionUpdateOptionsResult))] [JsonSerializable(typeof(SessionUsageGetMetricsRequest))] +[JsonSerializable(typeof(SessionUsageSetCodeChangesRequest))] [JsonSerializable(typeof(SessionVisibilityGetRequest))] [JsonSerializable(typeof(SessionWorkflowPauseAtCheckpointResult))] [JsonSerializable(typeof(SessionWorkingDirectoryContext))] +[JsonSerializable(typeof(SessionWorkingDirectoryContextWithClient))] [JsonSerializable(typeof(SessionWorkspacesAutopilotObjectiveExistsRequest))] [JsonSerializable(typeof(SessionWorkspacesDeleteAutopilotObjectiveRequest))] [JsonSerializable(typeof(SessionWorkspacesGetWorkspaceRequest))] @@ -51410,6 +57966,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionsClientMetadataEntry))] [JsonSerializable(typeof(SessionsCloseRequest))] [JsonSerializable(typeof(SessionsCloseResult))] +[JsonSerializable(typeof(SessionsCreateWorkspaceRequest))] +[JsonSerializable(typeof(SessionsCreateWorkspaceResult))] [JsonSerializable(typeof(SessionsDeleteRequest))] [JsonSerializable(typeof(SessionsEnrichMetadataRequest))] [JsonSerializable(typeof(SessionsFindByPrefixRequest))] @@ -51433,6 +57991,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionsListNonEmptySessionIdsResult))] [JsonSerializable(typeof(SessionsListRequest))] [JsonSerializable(typeof(SessionsLoadDeferredRepoHooksRequest))] +[JsonSerializable(typeof(SessionsLoadWorkspaceRequest))] +[JsonSerializable(typeof(SessionsLoadWorkspaceResult))] [JsonSerializable(typeof(SessionsOpenProgress))] [JsonSerializable(typeof(SessionsPruneOldRequest))] [JsonSerializable(typeof(SessionsReadPersistedEventsRequest))] @@ -51448,7 +58008,10 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionsStartRemoteControlRequest))] [JsonSerializable(typeof(SessionsStopRemoteControlRequest))] [JsonSerializable(typeof(SessionsTransferRemoteControlRequest))] +[JsonSerializable(typeof(SessionsUpdateWorkspaceFieldsRequest))] +[JsonSerializable(typeof(SessionsUpdateWorkspaceFieldsResult))] [JsonSerializable(typeof(SettableAuthInfo))] +[JsonSerializable(typeof(SettingsEditResult))] [JsonSerializable(typeof(ShellCancelUserRequestedRequest))] [JsonSerializable(typeof(ShellCredentials))] [JsonSerializable(typeof(ShellExecRequest))] @@ -51495,7 +58058,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SlashCommandInput))] [JsonSerializable(typeof(SlashCommandInputChoice))] [JsonSerializable(typeof(SlashCommandInvocationResult))] -[JsonSerializable(typeof(SlashCommandInvocationResultSetModelRevertOnCancel))] [JsonSerializable(typeof(SlashCommandModelPickerDialog))] [JsonSerializable(typeof(SlashCommandSelectSubcommandOption))] [JsonSerializable(typeof(SlashCommandTimelineEntry))] @@ -51540,6 +58102,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ToolsGetBuiltinDescriptorsResult))] [JsonSerializable(typeof(ToolsGetCurrentMetadataResult))] [JsonSerializable(typeof(ToolsInitializeAndValidateResult))] +[JsonSerializable(typeof(ToolsListPendingRequestsRequest))] [JsonSerializable(typeof(ToolsListRequest))] [JsonSerializable(typeof(ToolsSetRequest))] [JsonSerializable(typeof(ToolsSetResult))] @@ -51558,7 +58121,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(UIHandlePendingExitPlanModeRequest))] [JsonSerializable(typeof(UIHandlePendingResult))] [JsonSerializable(typeof(UIHandlePendingSamplingRequest))] -[JsonSerializable(typeof(UIHandlePendingSamplingResponse))] [JsonSerializable(typeof(UIHandlePendingSessionLimitsExhaustedRequest))] [JsonSerializable(typeof(UIHandlePendingUserInputRequest))] [JsonSerializable(typeof(UIRegisterDirectAutoModeSwitchHandlerResult))] @@ -51568,19 +58130,54 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(UIUserInputResponse))] [JsonSerializable(typeof(UpdateSubagentSettingsRequest))] [JsonSerializable(typeof(UpdateSubagentSettingsRequestSubagents))] -[JsonSerializable(typeof(UsageGetMetricsResult))] -[JsonSerializable(typeof(UsageMetricsAgentMetric))] -[JsonSerializable(typeof(UsageMetricsCodeChanges))] -[JsonSerializable(typeof(UsageMetricsModelMetric))] -[JsonSerializable(typeof(UsageMetricsModelMetricRequests))] -[JsonSerializable(typeof(UsageMetricsModelMetricTokenDetail))] -[JsonSerializable(typeof(UsageMetricsModelMetricUsage))] -[JsonSerializable(typeof(UsageMetricsTokenDetail))] [JsonSerializable(typeof(UserRequestedShellCommandResult))] [JsonSerializable(typeof(UserSettingMetadata))] +[JsonSerializable(typeof(UserSettingsApplyTopKeyRequest))] +[JsonSerializable(typeof(UserSettingsApplyTopKeyResult))] +[JsonSerializable(typeof(UserSettingsBuildRuntimeRequest))] +[JsonSerializable(typeof(UserSettingsEditRequest))] +[JsonSerializable(typeof(UserSettingsGetPathsRequest))] +[JsonSerializable(typeof(UserSettingsGetPathsResult))] [JsonSerializable(typeof(UserSettingsGetResult))] +[JsonSerializable(typeof(UserSettingsGovernanceKeysResult))] +[JsonSerializable(typeof(UserSettingsHostContext))] +[JsonSerializable(typeof(UserSettingsLoadAndMergeRepoRequest))] +[JsonSerializable(typeof(UserSettingsLoadAndMergeRepoResult))] +[JsonSerializable(typeof(UserSettingsLoadForConfigDirRequest))] +[JsonSerializable(typeof(UserSettingsLoadForEditResult))] +[JsonSerializable(typeof(UserSettingsLoadRepoRequest))] +[JsonSerializable(typeof(UserSettingsLoadRepoResult))] +[JsonSerializable(typeof(UserSettingsLoadWithWarningResult))] +[JsonSerializable(typeof(UserSettingsMergeManagedAndUserParams))] +[JsonSerializable(typeof(UserSettingsMergeManagedAndUserResult))] +[JsonSerializable(typeof(UserSettingsMergeRepoValueParams))] +[JsonSerializable(typeof(UserSettingsMergeRepoValueResult))] +[JsonSerializable(typeof(UserSettingsMigrateObsoleteOnDiskRequest))] +[JsonSerializable(typeof(UserSettingsMigrateObsoleteOnDiskResult))] +[JsonSerializable(typeof(UserSettingsMigrateStaffLogLevelOnceRequest))] +[JsonSerializable(typeof(UserSettingsMigrateStaffLogLevelOnceResult))] +[JsonSerializable(typeof(UserSettingsMigrateStaffUpdateChannelOnceResult))] +[JsonSerializable(typeof(UserSettingsNormalizeRequest))] +[JsonSerializable(typeof(UserSettingsNormalizeResult))] +[JsonSerializable(typeof(UserSettingsPathResult))] +[JsonSerializable(typeof(UserSettingsProblem))] +[JsonSerializable(typeof(UserSettingsProblemLocation))] +[JsonSerializable(typeof(UserSettingsProblemSource))] +[JsonSerializable(typeof(UserSettingsProblemsRequest))] +[JsonSerializable(typeof(UserSettingsProblemsResult))] +[JsonSerializable(typeof(UserSettingsResetStaffModelSelectionOnceRequest))] +[JsonSerializable(typeof(UserSettingsResetStaffModelSelectionOnceResult))] +[JsonSerializable(typeof(UserSettingsSetHookDisabledRequest))] +[JsonSerializable(typeof(UserSettingsSetHookDisabledResult))] [JsonSerializable(typeof(UserSettingsSetRequest))] -[JsonSerializable(typeof(UserSettingsSetResult))] +[JsonSerializable(typeof(UserSettingsUnknownKeysWarningRequest))] +[JsonSerializable(typeof(UserSettingsUnknownKeysWarningResult))] +[JsonSerializable(typeof(UserSettingsUpdateRequest))] +[JsonSerializable(typeof(UserSettingsUpdateResult))] +[JsonSerializable(typeof(UserSettingsValidateRequest))] +[JsonSerializable(typeof(UserSettingsValidateResult))] +[JsonSerializable(typeof(UserSettingsValidationIssue))] +[JsonSerializable(typeof(UserSettingsWriteAllRequest))] [JsonSerializable(typeof(VisibilityGetResult))] [JsonSerializable(typeof(VisibilitySetRequest))] [JsonSerializable(typeof(VisibilitySetResult))] @@ -51624,18 +58221,18 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(WorkflowToolResumeRequest))] [JsonSerializable(typeof(WorkflowToolRunOptions))] [JsonSerializable(typeof(WorkflowToolRunRequest))] +[JsonSerializable(typeof(WorkspaceDiffContents))] [JsonSerializable(typeof(WorkspaceDiffFileChange))] [JsonSerializable(typeof(WorkspaceDiffResult))] [JsonSerializable(typeof(WorkspacesAddSummaryRequest))] [JsonSerializable(typeof(WorkspacesAddSummaryResult))] -[JsonSerializable(typeof(WorkspacesAddSummaryResultSummary))] -[JsonSerializable(typeof(WorkspacesAddSummaryResultWorkspace))] [JsonSerializable(typeof(WorkspacesAutopilotObjectiveExistsResult))] [JsonSerializable(typeof(WorkspacesCheckpoints))] [JsonSerializable(typeof(WorkspacesCreateDirectoryRequest))] [JsonSerializable(typeof(WorkspacesCreateFileRequest))] [JsonSerializable(typeof(WorkspacesDeleteAutopilotObjectiveResult))] [JsonSerializable(typeof(WorkspacesDiffRequest))] +[JsonSerializable(typeof(WorkspacesDiffRequestWithSession))] [JsonSerializable(typeof(WorkspacesEnsureRequest))] [JsonSerializable(typeof(WorkspacesGetWorkspaceResult))] [JsonSerializable(typeof(WorkspacesGetWorkspaceResultWorkspace))] diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs index c482a8a69f..190624d478 100644 --- a/dotnet/src/Generated/SessionEvents.cs +++ b/dotnet/src/Generated/SessionEvents.cs @@ -119,6 +119,7 @@ namespace GitHub.Copilot; [JsonDerivedType(typeof(SessionIdleEvent), "session.idle")] [JsonDerivedType(typeof(SessionIndexedSearchEvent), "session.indexed_search")] [JsonDerivedType(typeof(SessionInfoEvent), "session.info")] +[JsonDerivedType(typeof(SessionManagedPluginProgressEvent), "session.managed_plugin_progress")] [JsonDerivedType(typeof(SessionManagedSettingsEnforcedEvent), "session.managed_settings_enforced")] [JsonDerivedType(typeof(SessionManagedSettingsResolvedEvent), "session.managed_settings_resolved")] [JsonDerivedType(typeof(SessionMcpServerNeedsReconnectEvent), "session.mcp_server_needs_reconnect")] @@ -132,6 +133,7 @@ namespace GitHub.Copilot; [JsonDerivedType(typeof(SessionPermissionRecoveryEvent), "session.permission_recovery")] [JsonDerivedType(typeof(SessionPermissionsChangedEvent), "session.permissions_changed")] [JsonDerivedType(typeof(SessionPlanChangedEvent), "session.plan_changed")] +[JsonDerivedType(typeof(SessionQuotaObservationEvent), "session.quota_observation")] [JsonDerivedType(typeof(SessionRemoteSteerableChangedEvent), "session.remote_steerable_changed")] [JsonDerivedType(typeof(SessionResumeEvent), "session.resume")] [JsonDerivedType(typeof(SessionScheduleCancelledEvent), "session.schedule_cancelled")] @@ -483,6 +485,8 @@ internal sealed partial class SessionEventJsonConverter : JsonConverterA provider-owned quota observation, distinct from per-call usage and charge accounting. +/// Represents the session.quota_observation event. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class SessionQuotaObservationEvent : SessionEvent +{ + /// + [JsonIgnore] + public override string Type => "session.quota_observation"; + + /// The session.quota_observation event payload. + [JsonPropertyName("data")] + public required SessionQuotaObservationData Data { get; set; } +} + /// Working directory and git context at session start. /// Represents the session.context_changed event. public sealed partial class SessionContextChangedEvent : SessionEvent @@ -2347,6 +2367,20 @@ public sealed partial class SessionAutoModeResolvedEvent : SessionEvent public required SessionAutoModeResolvedData Data { get; set; } } +/// Experimental transient presentation-neutral progress for organization-required plugin preparation. Clients should localize the phase copy and display plugin specs without translating them. +/// Represents the session.managed_plugin_progress event. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class SessionManagedPluginProgressEvent : SessionEvent +{ + /// + [JsonIgnore] + public override string Type => "session.managed_plugin_progress"; + + /// The session.managed_plugin_progress event payload. + [JsonPropertyName("data")] + public required SessionManagedPluginProgressData Data { get; set; } +} + /// Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. /// Represents the session.managed_settings_resolved event. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] @@ -2361,7 +2395,7 @@ public sealed partial class SessionManagedSettingsResolvedEvent : SessionEvent public required SessionManagedSettingsResolvedData Data { get; set; } } -/// Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on a bypass-permissions escalation while policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. +/// Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on bypass permissions or Assisted Permissions while the corresponding policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. /// Represents the session.managed_settings_enforced event. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed partial class SessionManagedSettingsEnforcedEvent : SessionEvent @@ -2761,6 +2795,11 @@ public sealed partial class SessionStartData [JsonPropertyName("autoTier")] public AutoTier? AutoTier { get; set; } + /// True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("autoTierManaged")] + public bool? AutoTierManaged { get; set; } + /// Working directory and git context at session start. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("context")] @@ -2771,6 +2810,11 @@ public sealed partial class SessionStartData [JsonPropertyName("contextTier")] public ContextTier? ContextTier { get; set; } + /// True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("contextTierManaged")] + public bool? ContextTierManaged { get; set; } + /// Version string of the Copilot application. [JsonPropertyName("copilotVersion")] public required string CopilotVersion { get; set; } @@ -2789,11 +2833,21 @@ public sealed partial class SessionStartData [JsonPropertyName("producer")] public required string Producer { get; set; } + /// Provider of selectedModel at creation time, when explicitly selected. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + /// Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } + /// True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningEffortManaged")] + public bool? ReasoningEffortManaged { get; set; } + /// Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffortModel")] @@ -2850,6 +2904,11 @@ public sealed partial class SessionResumeData [JsonPropertyName("autoTier")] public AutoTier? AutoTier { get; set; } + /// True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("autoTierManaged")] + public bool? AutoTierManaged { get; set; } + /// Updated working directory and git context at resume time. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("context")] @@ -2860,6 +2919,11 @@ public sealed partial class SessionResumeData [JsonPropertyName("contextTier")] public ContextTier? ContextTier { get; set; } + /// True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("contextTierManaged")] + public bool? ContextTierManaged { 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 or omitted, pending work is normally marked as interrupted unless the resume passively joined live work owned by another client; sessionWasActive distinguishes that case. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("continuePendingWork")] @@ -2874,11 +2938,21 @@ public sealed partial class SessionResumeData [JsonPropertyName("eventsFileSizeBytes")] public long? EventsFileSizeBytes { get; set; } + /// Provider of selectedModel at resume time, when explicitly selected. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + /// Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } + /// True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningEffortManaged")] + public bool? ReasoningEffortManaged { get; set; } + /// Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffortModel")] @@ -2940,7 +3014,7 @@ public sealed partial class SessionErrorData [JsonPropertyName("errorCode")] public string? ErrorCode { get; set; } - /// Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query"). + /// Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query"). [JsonPropertyName("errorType")] public required string ErrorType { get; set; } @@ -2953,6 +3027,16 @@ public sealed partial class SessionErrorData [JsonPropertyName("providerCallId")] public string? ProviderCallId { get; set; } + /// Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerErrorParam")] + public string? ProviderErrorParam { get; set; } + + /// Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerErrorType")] + public string? ProviderErrorType { get; set; } + /// What the user must do to recover, when the runtime knows of an action. The `message` never names a client affordance, so a client that offers one — a slash command, a settings pane, a link — renders it from this value. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("remediation")] @@ -3161,6 +3245,11 @@ public sealed partial class SessionModelChangeData [JsonPropertyName("autoTier")] public AutoTier? AutoTier { get; set; } + /// True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("autoTierManaged")] + public bool? AutoTierManaged { get; set; } + /// Reason the change happened, when not user-initiated. `"rate_limit_auto_switch"` for changes triggered by the auto-mode-switch rate-limit recovery path, or `"refusal_fallback"` when the active model declined a request (content refusal) and the runtime switched to the configured refusal-fallback model. UI clients can use this to render contextual copy. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("cause")] @@ -3171,6 +3260,11 @@ public sealed partial class SessionModelChangeData [JsonPropertyName("contextTier")] public ContextTier? ContextTier { get; set; } + /// True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("contextTierManaged")] + public bool? ContextTierManaged { get; set; } + /// Newly selected model identifier. [JsonPropertyName("newModel")] public required string NewModel { get; set; } @@ -3185,6 +3279,11 @@ public sealed partial class SessionModelChangeData [JsonPropertyName("previousModel")] public string? PreviousModel { get; set; } + /// Provider of previousModel, when known. A provider-only change is a model selection change even when the model identifiers are equal. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("previousProviderId")] + public string? PreviousProviderId { get; set; } + /// Reasoning effort level before the model change, if applicable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("previousReasoningEffort")] @@ -3200,11 +3299,21 @@ public sealed partial class SessionModelChangeData [JsonPropertyName("previousVerbosity")] public Verbosity? PreviousVerbosity { get; set; } + /// Provider selected for newModel. Omitted for legacy or unattributed selections; never inferred from a later selection. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + /// Reasoning effort level after the model change, if applicable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } + /// True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningEffortManaged")] + public bool? ReasoningEffortManaged { get; set; } + /// Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningEffortModel")] @@ -3438,6 +3547,12 @@ public sealed partial class SessionSnapshotRewindData /// Session termination metrics including usage statistics, code changes, and shutdown reason. public sealed partial class SessionShutdownData { + /// Complete accounting state captured atomically with receipt watermarks. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("accountingSnapshot")] + internal UsageGetMetricsResult? AccountingSnapshot { get; set; } + /// Per-agent usage breakdown, keyed by agent instance identifier. The main conversation uses the stable key `main`. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("agentMetrics")] @@ -3476,6 +3591,11 @@ public sealed partial class SessionShutdownData [JsonPropertyName("modelMetrics")] public required IDictionary ModelMetrics { get; set; } + /// Provider/model accounting preserved for replay without consulting current provider selection. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerModelMetrics")] + public UsageMetricsProviderModelMetric[]? ProviderModelMetrics { get; set; } + /// Unix timestamp (milliseconds) when the session started. [JsonPropertyName("sessionStartTime")] public required long SessionStartTime { get; set; } @@ -3515,11 +3635,22 @@ public sealed partial class SessionShutdownData [JsonInclude] [JsonPropertyName("totalPremiumRequests")] internal double? TotalPremiumRequests { get; set; } + + /// Per-source accounting sequence watermarks subsuming preceding usage receipts. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("usageAccountingWatermarks")] + public IDictionary? UsageAccountingWatermarks { get; set; } } /// Durable session usage checkpoint for reconstructing aggregate accounting on resume. public sealed partial class SessionUsageCheckpointData { + /// Complete accounting state captured atomically with the receipt watermarks. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("accountingSnapshot")] + internal UsageGetMetricsResult? AccountingSnapshot { get; set; } + /// Internal per-model prompt-cache state used to restore expiration tracking on resume. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonInclude] @@ -3532,6 +3663,11 @@ public sealed partial class SessionUsageCheckpointData [JsonPropertyName("promptCacheBreakState")] internal JsonElement[]? PromptCacheBreakState { get; set; } + /// Provider/model accounting snapshot that subsumes preceding usage receipts. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerModelMetrics")] + public UsageMetricsProviderModelMetric[]? ProviderModelMetrics { get; set; } + /// Session-wide accumulated nano-AI units cost at checkpoint time. [JsonPropertyName("totalNanoAiu")] public required double TotalNanoAiu { get; set; } @@ -3541,6 +3677,20 @@ public sealed partial class SessionUsageCheckpointData [JsonInclude] [JsonPropertyName("totalPremiumRequests")] internal double? TotalPremiumRequests { get; set; } + + /// Highest accounted sequence per source session; no per-call deduplication history is retained. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("usageAccountingWatermarks")] + public IDictionary? UsageAccountingWatermarks { get; set; } +} + +/// A provider-owned quota observation, distinct from per-call usage and charge accounting. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class SessionQuotaObservationData +{ + /// The admitted provider's state observation. Admission balances and percentages remain absent; separate monthly usage may report its own amount and cycle. + [JsonPropertyName("observation")] + public required ProviderQuotaState Observation { get; set; } } /// Working directory and git context at session start. @@ -4156,6 +4306,16 @@ public sealed partial class SessionPermissionRecoveryData [JsonPropertyName("onBlocked")] public required PermissionRecoveryOnBlocked OnBlocked { get; set; } + /// Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerAgentId")] + public string? OwnerAgentId { get; set; } + + /// Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerSessionId")] + public string? OwnerSessionId { get; set; } + /// Controlled reason for the latest episode transition. [JsonPropertyName("reason")] public required PermissionRecoveryReason Reason { get; set; } @@ -4735,6 +4895,11 @@ public sealed partial class AssistantMessageData [JsonPropertyName("phase")] public string? Phase { get; set; } + /// Opaque origin provider identity captured at dispatch. Only an exact match with the target provider permits replay of reasoningOpaque, encryptedContent, reasoningBlocks, serverTools, and provider response/item identifiers. Matching model ids or wire protocols is insufficient. Omitted for legacy or unattributed messages; the runtime excludes unproven opaque state when projecting to a known provider. Text content and client tool requests/results remain portable semantic history. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + /// Neutral provider-tagged reasoning content blocks preserved verbatim for round-tripping. `reasoningText` and `reasoningOpaque` are a lossy derived view of these blocks, retained for display. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningBlocks")] @@ -4857,6 +5022,16 @@ public sealed partial class AssistantUsageData [JsonPropertyName("acceptedPredictionTokens")] public long? AcceptedPredictionTokens { get; set; } + /// Runtime-owned identity shared with the durable accounting receipt. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("accounting")] + public UsageAccountingIdentity? Accounting { get; set; } + + /// Availability of this call's reported AI-credit amount. Missing billing is unavailable, not a zero charge. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("aiCreditsStatus")] + public AiCreditsStatus? AiCreditsStatus { get; set; } + /// Completion ID from the model provider (e.g., chatcmpl-abc123). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("apiCallId")] @@ -4989,6 +5164,11 @@ public sealed partial class AssistantUsageData [JsonPropertyName("model")] public required string Model { get; set; } + /// Model display name captured for this call, not derived from the current selection. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("modelDisplayName")] + public string? ModelDisplayName { get; set; } + /// Fixed-set provider family serving the bring-your-own-key model (for example "openai", "anthropic", "azure_openai", "ollama", "llama_cpp", or "other"). Never the caller-supplied provider name. Absent for Copilot-served models. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("modelProvider")] @@ -5022,6 +5202,11 @@ public sealed partial class AssistantUsageData [JsonPropertyName("parentToolCallId")] public string? ParentToolCallId { get; set; } + /// Provider identity and product label captured by the actual call's dispatch path. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("provider")] + public ModelProviderRef? Provider { get; set; } + /// GitHub request tracing ID (x-github-request-id header) for server-side log correlation. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("providerCallId")] @@ -5053,6 +5238,21 @@ public sealed partial class AssistantUsageData [JsonPropertyName("rejectedPredictionTokens")] public long? RejectedPredictionTokens { get; set; } + /// Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyBytes")] + public long? RequestBodyBytes { get; set; } + + /// Content-Encoding applied to the request body of the attempt that produced this outcome; identity when uncompressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyEncoding")] + public ModelCallRequestBodyEncoding? RequestBodyEncoding { get; set; } + + /// Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyWireBytes")] + public long? RequestBodyWireBytes { get; set; } + /// Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("rte")] @@ -5097,6 +5297,42 @@ public sealed partial class AssistantUsageData [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("transport")] public AssistantUsageTransport? Transport { get; set; } + + /// Milliseconds spent on the WebSocket attempt before falling back to HTTP. + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackAfterMs")] + public TimeSpan? WebsocketFallbackAfter { get; set; } + + /// WebSocket close code received before the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackCloseCode")] + public int? WebsocketFallbackCloseCode { get; set; } + + /// Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackErrorKind")] + public ModelCallWebSocketFallbackErrorKind? WebsocketFallbackErrorKind { get; set; } + + /// Why the call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackReason")] + public ModelCallWebSocketFallbackReason? WebsocketFallbackReason { get; set; } + + /// Whether a WebSocket reconnect was attempted before falling back to HTTP. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackReconnectAttempted")] + public bool? WebsocketFallbackReconnectAttempted { get; set; } + + /// Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStartedThisCall")] + public bool? WebsocketFallbackStartedThisCall { get; set; } + + /// HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStatusCode")] + public int? WebsocketFallbackStatusCode { get; set; } } /// A detected loss of a previously cached prompt prefix. @@ -5351,11 +5587,31 @@ public sealed partial class ModelCallFailureData [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } + /// Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyBytes")] + public long? RequestBodyBytes { get; set; } + + /// Content-Encoding applied to the failed request body; identity when uncompressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyEncoding")] + public ModelCallRequestBodyEncoding? RequestBodyEncoding { get; set; } + + /// Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyWireBytes")] + public long? RequestBodyWireBytes { get; set; } + /// Content-free structural summary of the failing request. Contains only counts and shape flags (no prompt content), so it is safe for unrestricted telemetry. Populated only for client-error (4xx) failures. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("requestFingerprint")] public ModelCallFailureRequestFingerprint? RequestFingerprint { get; set; } + /// Zero-based orchestrator retry index of the failed attempt. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("retryAttempt")] + public long? RetryAttempt { get; set; } + /// Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("rte")] @@ -5379,6 +5635,42 @@ public sealed partial class ModelCallFailureData [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("transport")] public ModelCallFailureTransport? Transport { get; set; } + + /// Milliseconds spent on the WebSocket attempt before falling back to HTTP. + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackAfterMs")] + public TimeSpan? WebsocketFallbackAfter { get; set; } + + /// WebSocket close code received before the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackCloseCode")] + public int? WebsocketFallbackCloseCode { get; set; } + + /// Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackErrorKind")] + public ModelCallWebSocketFallbackErrorKind? WebsocketFallbackErrorKind { get; set; } + + /// Why the failed call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackReason")] + public ModelCallWebSocketFallbackReason? WebsocketFallbackReason { get; set; } + + /// Whether a WebSocket reconnect was attempted before falling back to HTTP. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackReconnectAttempted")] + public bool? WebsocketFallbackReconnectAttempted { get; set; } + + /// Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStartedThisCall")] + public bool? WebsocketFallbackStartedThisCall { get; set; } + + /// HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStatusCode")] + public int? WebsocketFallbackStatusCode { get; set; } } /// Internal telemetry result for one logical model operation after all orchestrator-owned retries settle. @@ -6354,6 +6646,16 @@ public sealed partial class PermissionRequestedData [JsonPropertyName("agentMode")] public SessionMode? AgentMode { get; set; } + /// Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerAgentId")] + public string? OwnerAgentId { get; set; } + + /// Execution session that owns permission recovery for this request. Absent on historical events. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerSessionId")] + public string? OwnerSessionId { get; set; } + /// Permission mode captured when evaluation began. Absent on historical events. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("permissionMode")] @@ -7076,11 +7378,24 @@ public sealed partial class SessionAutoModeResolvedData public bool? StickyOverride { get; set; } } +/// Experimental transient presentation-neutral progress for organization-required plugin preparation. Clients should localize the phase copy and display plugin specs without translating them. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class SessionManagedPluginProgressData +{ + /// Current preparation phase. + [JsonPropertyName("phase")] + public required ManagedPluginProgressPhase Phase { get; set; } + + /// Ordered plugin install specs affected by this phase. Empty while managed settings initialize and when preparation completes. + [JsonPropertyName("pluginSpecs")] + public required string[] PluginSpecs { get; set; } +} + /// Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed partial class SessionManagedSettingsResolvedData { - /// Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. [JsonPropertyName("bypassPermissionsDisabled")] public required bool BypassPermissionsDisabled { get; set; } @@ -7093,7 +7408,7 @@ public sealed partial class SessionManagedSettingsResolvedData [JsonPropertyName("deviceManaged")] public required bool DeviceManaged { get; set; } - /// Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. [JsonPropertyName("failClosed")] public required bool FailClosed { get; set; } @@ -7106,6 +7421,11 @@ public sealed partial class SessionManagedSettingsResolvedData [JsonPropertyName("permissionsAllowIntersected")] public bool? PermissionsAllowIntersected { get; set; } + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } + /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("policyHelperManaged")] @@ -7130,7 +7450,7 @@ public sealed partial class SessionManagedSettingsResolvedData public required ManagedSettingsResolvedSource Source { get; set; } } -/// Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on a bypass-permissions escalation while policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. +/// Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on bypass permissions or Assisted Permissions while the corresponding policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed partial class SessionManagedSettingsEnforcedData { @@ -7138,7 +7458,7 @@ public sealed partial class SessionManagedSettingsEnforcedData [JsonPropertyName("action")] public required ManagedSettingsEnforcedAction Action { get; set; } - /// For a `bypass_permissions_blocked` action, which permission-escalation primitive was refused. Absent for actions without a specific escalation primitive. + /// For a `bypass_permissions_blocked` action, which permission-mode or escalation primitive was refused. Absent for actions without a specific primitive. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("escalation")] public ManagedSettingsEnforcedEscalation? Escalation { get; set; } @@ -7151,7 +7471,7 @@ public sealed partial class SessionManagedSettingsEnforcedData [JsonPropertyName("message")] public required string Message { get; set; } - /// The managed setting key responsible for the enforcement (e.g. `permissions.disableBypassPermissionsMode`). + /// The managed setting key responsible for the enforcement (for example `permissions.disableBypassPermissionsMode` or `permissions.disableAssistedPermissionsMode`). [JsonPropertyName("setting")] public required string Setting { get; set; } } @@ -7823,85 +8143,90 @@ public sealed partial class HandoffRepository public required string Owner { get; set; } } -/// Request count and cost metrics. -/// Nested data type for ShutdownModelMetricRequests. -public sealed partial class ShutdownModelMetricRequests +/// Request count and cost metrics for this model. +/// Nested data type for UsageMetricsModelMetricRequests. +public sealed partial class UsageMetricsModelMetricRequests { - /// Cumulative cost multiplier for requests to this model. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + /// User-initiated premium request cost (with multiplier applied). [JsonPropertyName("cost")] - public double? Cost { get; set; } + public required double Cost { get; set; } - /// Total number of API requests made to this model. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + /// Number of API requests made with this model. [JsonPropertyName("count")] - public long? Count { get; set; } + public required long Count { get; set; } } -/// A token-type entry in a shutdown model metric, storing the accumulated token count. -/// Nested data type for ShutdownModelMetricTokenDetail. -public sealed partial class ShutdownModelMetricTokenDetail +/// Per-model token-detail entry containing the accumulated token count for one token type. +/// Nested data type for UsageMetricsModelMetricTokenDetail. +public sealed partial class UsageMetricsModelMetricTokenDetail { /// Accumulated token count for this token type. [JsonPropertyName("tokenCount")] public required long TokenCount { get; set; } } -/// Token usage breakdown. -/// Nested data type for ShutdownModelMetricUsage. -public sealed partial class ShutdownModelMetricUsage +/// Token usage metrics for this model. +/// Nested data type for UsageMetricsModelMetricUsage. +public sealed partial class UsageMetricsModelMetricUsage { - /// Total tokens read from prompt cache across all requests. + /// Total tokens read from prompt cache. [JsonPropertyName("cacheReadTokens")] public required long CacheReadTokens { get; set; } - /// Total tokens written to prompt cache across all requests. + /// Total tokens written to prompt cache. [JsonPropertyName("cacheWriteTokens")] public required long CacheWriteTokens { get; set; } - /// Total input tokens consumed across all requests to this model. + /// Total input tokens consumed. [JsonPropertyName("inputTokens")] public required long InputTokens { get; set; } - /// Total output tokens produced across all requests to this model. + /// Total output tokens produced. [JsonPropertyName("outputTokens")] public required long OutputTokens { get; set; } - /// Total reasoning tokens produced across all requests to this model. + /// Total output tokens used for reasoning. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("reasoningTokens")] public long? ReasoningTokens { get; set; } } -/// Per-model shutdown metrics with request counts, token usage, nano-AI units, and token details. -/// Nested data type for ShutdownModelMetric. -public sealed partial class ShutdownModelMetric +/// Per-model usage metrics, including request counts/costs, token usage, nano-AI units, and per-token-type details. +/// Nested data type for UsageMetricsModelMetric. +public sealed partial class UsageMetricsModelMetric { - /// Request count and cost metrics. + /// Completeness of this model's reported AI-credit subtotal. Explicitly reported zero is complete, not unavailable. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("aiCreditsStatus")] + public AiCreditsStatus? AiCreditsStatus { get; set; } + + /// Latest known prompt-cache expiration for this model. A timestamp in the past indicates that the observed cache has expired. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cacheExpiresAt")] + public DateTimeOffset? CacheExpiresAt { get; set; } + + /// Request count and cost metrics for this model. [JsonPropertyName("requests")] - public required ShutdownModelMetricRequests Requests { get; set; } + public required UsageMetricsModelMetricRequests Requests { get; set; } /// Token count details per type. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("tokenDetails")] - public IDictionary? TokenDetails { get; set; } + public IDictionary? TokenDetails { get; set; } /// Accumulated nano-AI units cost for this model. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("totalNanoAiu")] public double? TotalNanoAiu { get; set; } - /// Token usage breakdown. + /// Token usage metrics for this model. [JsonPropertyName("usage")] - public required ShutdownModelMetricUsage Usage { get; set; } + public required UsageMetricsModelMetricUsage Usage { get; set; } } -/// Usage attributed to one agent instance at session shutdown. -/// Nested data type for ShutdownAgentMetric. -public sealed partial class ShutdownAgentMetric +/// Usage attributed to one agent instance, including its identity, API duration, AI units, and per-model breakdown. +/// Nested data type for UsageMetricsAgentMetric. +public sealed partial class UsageMetricsAgentMetric { /// Human-readable label for this subagent invocation, copied from the originating `subagent.started` event. For task-tool subagents this is the invocation's task description rather than the agent's configured display name, so group by `agentName` for stable per-agent labels. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -7915,7 +8240,7 @@ public sealed partial class ShutdownAgentMetric /// Per-model usage for this agent, keyed by model identifier. [JsonPropertyName("modelMetrics")] - public required IDictionary ModelMetrics { get; set; } + public required IDictionary ModelMetrics { get; set; } /// Time spent in model API calls by this agent, in milliseconds. [JsonConverter(typeof(MillisecondsTimeSpanConverter))] @@ -7927,811 +8252,846 @@ public sealed partial class ShutdownAgentMetric public required double TotalNanoAiu { get; set; } } -/// Aggregate code change metrics for the session. -/// Nested data type for ShutdownCodeChanges. -public sealed partial class ShutdownCodeChanges +/// Aggregated code change metrics. +/// Nested data type for UsageMetricsCodeChanges. +public sealed partial class UsageMetricsCodeChanges { - /// List of file paths that were modified during the session. + /// Distinct file paths modified during the session. [JsonPropertyName("filesModified")] public required string[] FilesModified { get; set; } - /// Total number of lines added during the session. + /// Number of distinct files modified. + [JsonPropertyName("filesModifiedCount")] + public required long FilesModifiedCount { get; set; } + + /// Total lines of code added. [JsonPropertyName("linesAdded")] public required long LinesAdded { get; set; } - /// Total number of lines removed during the session. + /// Total lines of code removed. [JsonPropertyName("linesRemoved")] public required long LinesRemoved { get; set; } } -/// A session-wide shutdown token-type entry storing the accumulated token count. -/// Nested data type for ShutdownTokenDetail. -public sealed partial class ShutdownTokenDetail +/// A neutral reference to the model provider that produced a model: an opaque id, a human-readable label, and the provider kind. Carried on each enumerated Model so consumers can group by provider without reaching into a provider-shaped internal type. +/// Nested data type for ModelProviderRef. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class ModelProviderRef { - /// Accumulated token count for this token type. - [JsonPropertyName("tokenCount")] - public required long TokenCount { get; set; } + /// Opaque, stable id of the provider that produced this model. Matches the enumerated `ModelProviderDescriptor.id`. + [JsonPropertyName("id")] + public required string Id { get; set; } + + /// The provider kind. + [JsonPropertyName("kind")] + public required ModelProviderKind Kind { get; set; } + + /// Human-readable provider label, owned by the runtime so every consumer renders identical text. + [JsonPropertyName("label")] + public required string Label { get; set; } } -/// Internal prompt-cache expiration state for one model. -/// Nested data type for UsageCheckpointModelCacheState. -internal sealed partial class UsageCheckpointModelCacheState +/// Usage for one recorded provider and model, without merging identical model IDs across providers. +/// Nested data type for UsageMetricsProviderModelMetric. +public sealed partial class UsageMetricsProviderModelMetric { - /// Latest known prompt-cache expiration. - [JsonPropertyName("cacheExpiresAt")] - public required DateTimeOffset CacheExpiresAt { get; set; } + /// Request, token, and cost totals for this provider/model. + [JsonPropertyName("metrics")] + public required UsageMetricsModelMetric Metrics { get; set; } - /// Retained cache lifetime in seconds, used to refresh expiration after a cache read. - [JsonInclude] - [JsonPropertyName("cacheTtlSeconds")] - internal required long CacheTtlSeconds { get; set; } + /// Model display name captured at call time, when known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("modelDisplayName")] + public string? ModelDisplayName { get; set; } - /// Model identifier associated with this cache state. + /// Model identity, or null for legacy aggregate-only usage. [JsonPropertyName("modelId")] - public required string ModelId { get; set; } + public string? ModelId { get; set; } + + /// Provider identity and product label captured when the call was dispatched; null when unknown. + [JsonPropertyName("provider")] + public ModelProviderRef? Provider { get; set; } } -/// Token usage detail for a single billing category. -/// Nested data type for CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail. -public sealed partial class CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail +/// Session-wide token-detail entry containing the accumulated token count for one token type. +/// Nested data type for UsageMetricsTokenDetail. +public sealed partial class UsageMetricsTokenDetail { - /// Number of tokens in this billing batch. - [JsonPropertyName("batchSize")] - public required long BatchSize { get; set; } - - /// Cost per batch of tokens. - [JsonPropertyName("costPerBatch")] - public required long CostPerBatch { get; set; } - - /// Model responsible for this billing entry. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } - - /// Total token count for this entry. + /// Accumulated token count for this token type. [JsonPropertyName("tokenCount")] public required long TokenCount { get; set; } - - /// Token category (e.g., "input", "output"). - [JsonPropertyName("tokenType")] - public required string TokenType { get; set; } } -/// Per-request cost and usage data from the CAPI copilot_usage response field. -/// Nested data type for CompactionCompleteCompactionTokensUsedCopilotUsage. -internal sealed partial class CompactionCompleteCompactionTokensUsedCopilotUsage +/// Accumulated session usage metrics, including premium request cost, token counts, model breakdown, and code-change totals. +/// Nested data type for UsageGetMetricsResult. +public sealed partial class UsageGetMetricsResult { - /// Default billing model for token details that do not identify their own model. + /// Per-agent usage metrics, keyed by agent instance identifier. The main conversation uses the stable key `main`. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("model")] - internal string? Model { get; set; } + [JsonPropertyName("agentMetrics")] + public IDictionary? AgentMetrics { get; set; } - /// Itemized token usage breakdown. + /// Completeness of totalNanoAiu. Numeric totals remain the reported subtotal; zero is not a claim of free usage when unavailable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("tokenDetails")] - internal CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail[]? TokenDetails { get; set; } + [JsonPropertyName("aiCreditsStatus")] + public AiCreditsStatus? AiCreditsStatus { get; set; } - /// Total cost in nano-AI units for this request. - [JsonPropertyName("totalNanoAiu")] - public required double TotalNanoAiu { get; set; } -} + /// Aggregated code change metrics. + [JsonPropertyName("codeChanges")] + public required UsageMetricsCodeChanges CodeChanges { get; set; } -/// Token usage breakdown for the compaction LLM call (aligned with assistant.usage format). -/// Nested data type for CompactionCompleteCompactionTokensUsed. -public sealed partial class CompactionCompleteCompactionTokensUsed -{ - /// Cached input tokens reused in the compaction LLM call. + /// Currently active model identifier. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cacheReadTokens")] - public long? CacheReadTokens { get; set; } + [JsonPropertyName("currentModel")] + public string? CurrentModel { get; set; } - /// Tokens written to prompt cache in the compaction LLM call. + /// Input tokens from the most recent main-agent API call. + [JsonPropertyName("lastCallInputTokens")] + public required long LastCallInputTokens { get; set; } + + /// Output tokens from the most recent main-agent API call. + [JsonPropertyName("lastCallOutputTokens")] + public required long LastCallOutputTokens { get; set; } + + /// Per-model token and request metrics, keyed by model identifier. + [JsonPropertyName("modelMetrics")] + public required IDictionary ModelMetrics { get; set; } + + /// + /// Provider-attributed model metrics, ordered by first observed provider and model. + /// Null attribution preserves historical usage whose provider or model was not recorded. + /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cacheWriteTokens")] - public long? CacheWriteTokens { get; set; } + [JsonPropertyName("providerModelMetrics")] + public UsageMetricsProviderModelMetric[]? ProviderModelMetrics { get; set; } - /// Per-request cost and usage data from the CAPI copilot_usage response field. + /// ISO 8601 timestamp when the session started. + [JsonPropertyName("sessionStartTime")] + public required DateTimeOffset SessionStartTime { get; set; } + + /// Session-wide per-token-type accumulated token counts. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("copilotUsage")] - internal CompactionCompleteCompactionTokensUsedCopilotUsage? CopilotUsage { get; set; } + [JsonPropertyName("tokenDetails")] + public IDictionary? TokenDetails { get; set; } - /// Duration of the compaction LLM call in milliseconds. + /// Total time spent in model API calls (milliseconds). [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("duration")] - public TimeSpan? Duration { get; set; } + [JsonPropertyName("totalApiDurationMs")] + public required TimeSpan TotalApiDuration { get; set; } - /// Input tokens consumed by the compaction LLM call. + /// Session-wide accumulated nano-AI units cost. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("inputTokens")] - public long? InputTokens { get; set; } + [JsonPropertyName("totalNanoAiu")] + public double? TotalNanoAiu { get; set; } - /// Model identifier used for the compaction LLM call. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Total user-initiated premium request cost across all models (may be fractional due to multipliers). + [JsonPropertyName("totalPremiumRequestCost")] + public required double TotalPremiumRequestCost { get; set; } - /// Output tokens produced by the compaction LLM call. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputTokens")] - public long? OutputTokens { get; set; } + /// Raw count of user-initiated API requests. + [JsonPropertyName("totalUserRequests")] + public required long TotalUserRequests { get; set; } } -/// Original request-level and effective conversation reasoning effort for a provider history boundary; the historical type name is retained for compatibility. -/// Nested data type for ResponsesReasoning. -public sealed partial class ResponsesReasoning +/// Request count and cost metrics. +/// Nested data type for ShutdownModelMetricRequests. +public sealed partial class ShutdownModelMetricRequests { - /// Effective effort selected before this message, independent of the response-level reasoning field. - [JsonPropertyName("effort")] - public required string Effort { get; set; } + /// Cumulative cost multiplier for requests to this model. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cost")] + public double? Cost { get; set; } - /// Original request-level effort, retained while replaying this conversation prefix. - [JsonPropertyName("initialEffort")] - public required string InitialEffort { get; set; } + /// Total number of API requests made to this model. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("count")] + public long? Count { get; set; } +} - /// Provider model whose reasoning settings this boundary records. - [JsonPropertyName("model")] - public required string Model { get; set; } +/// A token-type entry in a shutdown model metric, storing the accumulated token count. +/// Nested data type for ShutdownModelMetricTokenDetail. +public sealed partial class ShutdownModelMetricTokenDetail +{ + /// Accumulated token count for this token type. + [JsonPropertyName("tokenCount")] + public required long TokenCount { get; set; } } -/// Nested data type for PermissionRecoveryAttempt. -public sealed partial class PermissionRecoveryAttempt +/// Token usage breakdown. +/// Nested data type for ShutdownModelMetricUsage. +public sealed partial class ShutdownModelMetricUsage { - /// Unique identifier for this attempt record. - [JsonPropertyName("attemptId")] - public required string AttemptId { get; set; } + /// Total tokens read from prompt cache across all requests. + [JsonPropertyName("cacheReadTokens")] + public required long CacheReadTokens { get; set; } - /// How the runtime handled this attempt. - [JsonPropertyName("disposition")] - public required PermissionRecoveryAttemptDisposition Disposition { get; set; } + /// Total tokens written to prompt cache across all requests. + [JsonPropertyName("cacheWriteTokens")] + public required long CacheWriteTokens { get; set; } - /// One-based position of this attempt in the episode. - [JsonPropertyName("ordinal")] - public required long Ordinal { get; set; } + /// Total input tokens consumed across all requests to this model. + [JsonPropertyName("inputTokens")] + public required long InputTokens { get; set; } - /// Controlled permission request kind, such as shell, path, URL, or tool. - [JsonPropertyName("permissionKind")] - public required string PermissionKind { get; set; } + /// Total output tokens produced across all requests to this model. + [JsonPropertyName("outputTokens")] + public required long OutputTokens { get; set; } - /// Controlled reason for the attempt disposition. - [JsonPropertyName("reason")] - public required PermissionRecoveryAttemptReason Reason { get; set; } + /// Total reasoning tokens produced across all requests to this model. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningTokens")] + public long? ReasoningTokens { get; set; } +} - /// Relationship between this attempt and earlier attempts in the episode. - [JsonPropertyName("relation")] - public required PermissionRecoveryAttemptRelation Relation { get; set; } +/// Per-model shutdown metrics with request counts, token usage, nano-AI units, and token details. +/// Nested data type for ShutdownModelMetric. +public sealed partial class ShutdownModelMetric +{ + /// Request count and cost metrics. + [JsonPropertyName("requests")] + public required ShutdownModelMetricRequests Requests { get; set; } - /// SHA-256 fingerprint of normalized request data; raw permission arguments are not included. - [JsonPropertyName("requestFingerprint")] - public required string RequestFingerprint { get; set; } + /// Token count details per type. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("tokenDetails")] + public IDictionary? TokenDetails { get; set; } - /// Tool-call identifier associated with this attempt, when available. + /// Accumulated nano-AI units cost for this model. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + [JsonPropertyName("totalNanoAiu")] + public double? TotalNanoAiu { get; set; } + + /// Token usage breakdown. + [JsonPropertyName("usage")] + public required ShutdownModelMetricUsage Usage { get; set; } } -/// Authoritative snapshot of an Autopilot permission-recovery episode. -/// Nested data type for PermissionRecoveryData. -public sealed partial class PermissionRecoveryData +/// Usage attributed to one agent instance at session shutdown. +/// Nested data type for ShutdownAgentMetric. +public sealed partial class ShutdownAgentMetric { - /// Ordered privacy-safe record of permission attempts and the successful alternative, when any. - [JsonPropertyName("attempts")] - public required PermissionRecoveryAttempt[] Attempts { get; set; } - - /// Stable identifier shared by every transition in this recovery episode. - [JsonPropertyName("episodeId")] - public required string EpisodeId { get; set; } + /// Human-readable label for this subagent invocation, copied from the originating `subagent.started` event. For task-tool subagents this is the invocation's task description rather than the agent's configured display name, so group by `agentName` for stable per-agent labels. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("agentDisplayName")] + public string? AgentDisplayName { get; set; } - /// Maximum number of distinct autonomous permission attempts allowed before escalation. - [JsonPropertyName("maxAttempts")] - public required long MaxAttempts { get; set; } + /// Configured agent name, when this is a subagent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("agentName")] + public string? AgentName { get; set; } - /// Policy selected from the current client's response capability; mode or client changes may update it during recovery. - [JsonPropertyName("onBlocked")] - public required PermissionRecoveryOnBlocked OnBlocked { get; set; } + /// Per-model usage for this agent, keyed by model identifier. + [JsonPropertyName("modelMetrics")] + public required IDictionary ModelMetrics { get; set; } - /// Controlled reason for the latest episode transition. - [JsonPropertyName("reason")] - public required PermissionRecoveryReason Reason { get; set; } + /// Time spent in model API calls by this agent, in milliseconds. + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonPropertyName("totalApiDurationMs")] + public required TimeSpan TotalApiDuration { get; set; } - /// Current lifecycle state of the recovery episode. - [JsonPropertyName("status")] - public required PermissionRecoveryStatus Status { get; set; } + /// Accumulated nano-AI units cost for this agent. + [JsonPropertyName("totalNanoAiu")] + public required double TotalNanoAiu { get; set; } } -/// Structured reason that the task cannot continue without intervention. -/// Nested data type for TaskBlocker. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class TaskBlocker +/// Aggregate code change metrics for the session. +/// Nested data type for ShutdownCodeChanges. +public sealed partial class ShutdownCodeChanges { - /// Category of intervention that blocked the task. - [JsonPropertyName("kind")] - public required TaskBlockerKind Kind { get; set; } + /// List of file paths that were modified during the session. + [JsonPropertyName("filesModified")] + public required string[] FilesModified { get; set; } - /// Permission-recovery episode that produced this blocker. - [JsonPropertyName("permissionRecovery")] - public required PermissionRecoveryData PermissionRecovery { get; set; } + /// Total number of lines added during the session. + [JsonPropertyName("linesAdded")] + public required long LinesAdded { get; set; } - /// Controlled reason for the current blocked state. - [JsonPropertyName("reason")] - public required PermissionRecoveryReason Reason { get; set; } + /// Total number of lines removed during the session. + [JsonPropertyName("linesRemoved")] + public required long LinesRemoved { get; set; } +} - /// Whether a later user response or steering message can resume the task. - [JsonPropertyName("resumable")] - public required bool Resumable { get; set; } +/// A session-wide shutdown token-type entry storing the accumulated token count. +/// Nested data type for ShutdownTokenDetail. +public sealed partial class ShutdownTokenDetail +{ + /// Accumulated token count for this token type. + [JsonPropertyName("tokenCount")] + public required long TokenCount { get; set; } } -/// Inclusive durable event range summarized by a completion receipt. -/// Nested data type for CompletionReceiptEventRange. -public sealed partial class CompletionReceiptEventRange +/// Internal prompt-cache expiration state for one model. +/// Nested data type for UsageCheckpointModelCacheState. +internal sealed partial class UsageCheckpointModelCacheState { - /// Identifier of the assistant turn-end event that ends the covered exchange. Always equals the receipt's sourceEventId, so either field is a valid join key. - [JsonPropertyName("endEventId")] - public required string EndEventId { get; set; } + /// Latest known prompt-cache expiration. + [JsonPropertyName("cacheExpiresAt")] + public required DateTimeOffset CacheExpiresAt { get; set; } - /// Identifier of the user message that starts the covered exchange. - [JsonPropertyName("startEventId")] - public required string StartEventId { get; set; } + /// Retained cache lifetime in seconds, used to refresh expiration after a cache read. + [JsonInclude] + [JsonPropertyName("cacheTtlSeconds")] + internal required long CacheTtlSeconds { get; set; } + + /// Model identifier associated with this cache state. + [JsonPropertyName("modelId")] + public required string ModelId { get; set; } } -/// Final structured tool completion in the covered event range. -/// Nested data type for CompletionReceiptFinalTool. -public sealed partial class CompletionReceiptFinalTool +/// Authoritative budget measurements and policy metadata, independent of provider. +/// Nested data type for ProviderQuotaBudgetMetadata. +public sealed partial class ProviderQuotaBudgetMetadata { - /// Process exit code from a structured shell result, when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } + /// Exact measured consumption in the budget's unit. + [JsonPropertyName("consumed")] + public required double Consumed { get; set; } - /// Structured success or failure status from the tool completion event. - [JsonPropertyName("status")] - public required CompletionReceiptToolStatus Status { get; set; } + /// Exact budget entitlement, retaining incumbent fractional-unit compatibility. + [JsonPropertyName("entitlement")] + public required double Entitlement { get; set; } - /// Unique identifier of the completed tool call. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } + /// Usage beyond entitlement, in the budget's unit. + [JsonPropertyName("overage")] + public required double Overage { get; set; } - /// Tool name from the matching tool execution start event, when available. + /// Whether additional usage is allowed when the budget is exhausted. + [JsonPropertyName("overageAllowedWhenExhausted")] + public required bool OverageAllowedWhenExhausted { get; set; } + + /// Optional additional-usage budget cap. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolName")] - public string? ToolName { get; set; } -} + [JsonPropertyName("overageLimit")] + public double? OverageLimit { get; set; } -/// Nested data type for FusionCritic. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class FusionCritic -{ - /// Concrete model selected for this critic. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("model")] - public required string Model { get; set; } + /// Service-reported remaining percentage for authoritative budget presentation. + [JsonPropertyName("remainingPercentage")] + public required double RemainingPercentage { get; set; } - /// Unique execution phase identifier for this critic. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("phaseId")] - public required string PhaseId { get; set; } + /// Reset instant in epoch milliseconds when this budget actually defines a window. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resetAtEpochMs")] + public double? ResetAtEpochMs { get; set; } - /// Explicit reasoning effort selected for this critic, if supplied. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + /// Whether the reset instant is an estimate. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } -} + [JsonPropertyName("resetEstimated")] + public bool? ResetEstimated { get; set; } -/// Durable server recommendation for subsequent HydraFusion turns. -/// Nested data type for FusionFollowUpRecommendation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class FusionFollowUpRecommendation -{ - /// Recommended routing action for the next compaction turn. - [JsonPropertyName("compactionTurn")] - public required FusionFollowUpAction CompactionTurn { get; set; } + /// Whether this budget uses token-based billing. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("tokenBasedBilling")] + public bool? TokenBasedBilling { get; set; } - /// Recommended routing action for the next user-message turn. - [JsonPropertyName("userTurn")] - public required FusionFollowUpAction UserTurn { get; set; } + /// Whether the budget has unlimited entitlement. + [JsonPropertyName("unlimited")] + public required bool Unlimited { get; set; } + + /// Whether service policy allows continued usage after exhaustion. + [JsonPropertyName("usageAllowedWhenExhausted")] + public required bool UsageAllowedWhenExhausted { get; set; } } -/// Presentation-neutral phase planned for a HydraFusion turn. -/// Nested data type for FusionPhasePlanStep. +/// An authoritative monthly usage reading for the observation's provider, account, and service. +/// Nested data type for ProviderMonthlyUsage. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class FusionPhasePlanStep +public sealed partial class ProviderMonthlyUsage { - /// Whether the phase executes only when an earlier phase requests it. - [JsonPropertyName("conditional")] - public required bool Conditional { get; set; } + /// Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("consumedQuantity")] + public double? ConsumedQuantity { get; set; } - /// Kind of phase that may execute. - [JsonPropertyName("kind")] - public required FusionPhaseKind Kind { get; set; } + /// Start of the service-reported monthly billing cycle, in UTC RFC 3339. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cycleStart")] + public string? CycleStart { get; set; } - /// Semantic role assigned to the phase. - [JsonPropertyName("role")] - public required string Role { get; set; } + /// Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("queriedAt")] + public string? QueriedAt { get; set; } - /// Conversation scope in which the phase executes. + /// End of the service-reported monthly billing cycle, in UTC RFC 3339. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resetOn")] + public string? ResetOn { get; set; } + + /// Identity scope of the reading within its provider and service. [JsonPropertyName("scope")] - public required FusionConversationScope Scope { get; set; } + public required ProviderMonthlyUsageScope Scope { get; set; } + + /// Availability of monthly consumption. Missing or unavailable usage must never be interpreted as zero. + [JsonPropertyName("state")] + public required ProviderMonthlyUsageState State { get; set; } + + /// Unit of consumedQuantity; independent of the parent observation's balance unit. + [JsonPropertyName("unit")] + public required ProviderQuotaUnit Unit { get; set; } } -/// Validated HydraFusion routing capability scores. -/// Nested data type for FusionScores. +/// An account quota reading. Absence of a quantity is unknown, never zero. +/// Nested data type for ProviderQuotaState. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class FusionScores +public sealed partial class ProviderQuotaState { - /// Code-generation capability score returned by the authenticated router. - [JsonPropertyName("codeGen")] - public required double CodeGen { get; set; } + /// Whether the service permits access, independently of balance. + [JsonPropertyName("accessState")] + public required ProviderQuotaAccessState AccessState { get; set; } - /// Debugging capability score returned by the authenticated router. - [JsonPropertyName("debugging")] - public required double Debugging { get; set; } + /// Service error code or client acquisition category, separate from the business-state reason. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("acquisitionError")] + public string? AcquisitionError { get; set; } - /// Reasoning capability score returned by the authenticated router. - [JsonPropertyName("reasoning")] - public required double Reasoning { get; set; } + /// Acquisition outcome. Unavailable/failed readings have no service verdict; access/capacity unavailable are compatibility placeholders only. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("acquisitionStatus")] + public ProviderQuotaAcquisitionStatus? AcquisitionStatus { get; set; } - /// Tool-use capability score returned by the authenticated router. - [JsonPropertyName("toolUse")] - public required double ToolUse { get; set; } -} + /// Independently reported signed 64-bit available quantity. Zero does not override the service access/capacity verdict; omission and null are preserved. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("availableQuantity")] + public long? AvailableQuantity { get; set; } -/// Optional line range to scope the attachment to a specific section of the file. -/// Nested data type for AttachmentFileLineRange. -public sealed partial class AttachmentFileLineRange -{ - /// End line number (1-based, inclusive). - [JsonPropertyName("end")] - public required long End { get; set; } + /// Optional metadata for an authoritative budget. Advisory balances and admission-only observations do not populate this. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("budgetMetadata")] + public ProviderQuotaBudgetMetadata? BudgetMetadata { get; set; } - /// Start line number (1-based). - [JsonPropertyName("start")] - public required long Start { get; set; } -} + /// Service capacity state; missing quantities do not imply exhaustion. + [JsonPropertyName("capacityState")] + public required ProviderQuotaCapacityState CapacityState { get; set; } -/// File attachment. -/// The file variant of . -public sealed partial class AttachmentFile : Attachment -{ - /// - [JsonIgnore] - public override string Type => "file"; + /// Key for the backwards-compatible snapshots projection, when the authoritative budget supports that contract. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("compatibilityKey")] + public string? CompatibilityKey { get; set; } - /// Internal: content-addressed id of the session.binary_asset event holding this attachment's model-facing bytes (e.g. "sha256:..."). Absent externally. + /// Independently reported signed 64-bit entitlement. -1 is an unlimited sentinel, not a capacity-state rewrite; omission and null are preserved. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("assetId")] - public string? AssetId { get; set; } + [JsonPropertyName("entitledQuantity")] + public long? EntitledQuantity { get; set; } - /// Internal: decoded byte length of the attachment's model-facing bytes. Absent externally. + /// Explicit service admission flag, when reported. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("byteLength")] - public long? ByteLength { get; set; } + [JsonPropertyName("hasQuota")] + public bool? HasQuota { get; set; } - /// User-facing display name for the attachment. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// HTTP status from acquisition, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("httpStatus")] + public long? HttpStatus { get; set; } - /// Optional line range to scope the attachment to a specific section of the file. + /// Service-reported monthly consumption, independent of quota balances and per-call or session cost. Omitted when the service does not report monthly usage. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("lineRange")] - public AttachmentFileLineRange? LineRange { get; set; } + [JsonPropertyName("monthlyUsage")] + public ProviderMonthlyUsage? MonthlyUsage { get; set; } - /// Internal: MIME type of the file's model-facing bytes (post-resize for images). Set when the file's bytes are interned to an asset. Absent externally. + /// Whether this is a GET account reading or a pre-response admission observation. Observations are never merged across kinds. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + [JsonPropertyName("observationKind")] + public ProviderQuotaObservationKind? ObservationKind { get; set; } - /// Internal: why model-facing bytes are absent from persistence. Absent externally. + /// When the runtime observed this reading, not a charge timestamp or guarantee that consumption has settled. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("omittedReason")] - public OmittedBinaryOmittedReason? OmittedReason { get; set; } + [JsonPropertyName("observedAt")] + public string? ObservedAt { get; set; } - /// Absolute file path. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Provider/account whose service reported this state. + [JsonPropertyName("provider")] + public required ModelProviderRef Provider { get; set; } - /// Frozen rendered line this attachment contributed to the <tagged_files> prompt block (e.g. "* /path (123 lines)"). Captured at send time so resumed history reproduces the exact text the model saw, independent of later filesystem changes. Present only for attachments routed to <tagged_files> (mutually exclusive with assetId, which marks bytes sent natively). + /// Whether quantities are authoritative budget measurements, advisory balances, or absent. Only authoritative budgets support percentage presentation. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("taggedFilesEntry")] - public string? TaggedFilesEntry { get; set; } -} + [JsonPropertyName("quantityKind")] + public ProviderQuotaQuantityKind? QuantityKind { get; set; } -/// Directory attachment. -/// The directory variant of . -public sealed partial class AttachmentDirectory : Attachment -{ - /// - [JsonIgnore] - public override string Type => "directory"; + /// Service-owned quota identifier within this provider. + [JsonPropertyName("quotaId")] + public required string QuotaId { get; set; } - /// User-facing display name for the attachment. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Service-reported explanation for the state. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reason")] + public string? Reason { get; set; } - /// Absolute directory path. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Service name owning this reading. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("service")] + public string? Service { get; set; } - /// Frozen rendered line this attachment contributed to the <tagged_files> prompt block (e.g. "* /path (12 items)"). Captured at send time so resumed history reproduces the exact text the model saw, independent of later filesystem changes. + /// Service-reported quota source. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("taggedFilesEntry")] - public string? TaggedFilesEntry { get; set; } + [JsonPropertyName("source")] + public string? Source { get; set; } + + /// Unit of entitledQuantity and availableQuantity. + [JsonPropertyName("unit")] + public required ProviderQuotaUnit Unit { get; set; } } -/// End position of the selection. -/// Nested data type for AttachmentSelectionDetailsEnd. -public sealed partial class AttachmentSelectionDetailsEnd +/// Token usage detail for a single billing category. +/// Nested data type for CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail. +public sealed partial class CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail { - /// End character offset within the line (0-based). - [JsonPropertyName("character")] - public required long Character { get; set; } + /// Number of tokens in this billing batch. + [JsonPropertyName("batchSize")] + public required long BatchSize { get; set; } - /// End line number (0-based). - [JsonPropertyName("line")] - public required long Line { get; set; } -} + /// Cost per batch of tokens. + [JsonPropertyName("costPerBatch")] + public required long CostPerBatch { get; set; } -/// Start position of the selection. -/// Nested data type for AttachmentSelectionDetailsStart. -public sealed partial class AttachmentSelectionDetailsStart -{ - /// Start character offset within the line (0-based). - [JsonPropertyName("character")] - public required long Character { get; set; } + /// Model responsible for this billing entry. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Start line number (0-based). - [JsonPropertyName("line")] - public required long Line { get; set; } + /// Total token count for this entry. + [JsonPropertyName("tokenCount")] + public required long TokenCount { get; set; } + + /// Token category (e.g., "input", "output"). + [JsonPropertyName("tokenType")] + public required string TokenType { get; set; } } -/// Position range of the selection within the file. -/// Nested data type for AttachmentSelectionDetails. -public sealed partial class AttachmentSelectionDetails +/// Per-request cost and usage data from the CAPI copilot_usage response field. +/// Nested data type for CompactionCompleteCompactionTokensUsedCopilotUsage. +internal sealed partial class CompactionCompleteCompactionTokensUsedCopilotUsage { - /// End position of the selection. - [JsonPropertyName("end")] - public required AttachmentSelectionDetailsEnd End { get; set; } + /// Default billing model for token details that do not identify their own model. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("model")] + internal string? Model { get; set; } - /// Start position of the selection. - [JsonPropertyName("start")] - public required AttachmentSelectionDetailsStart Start { get; set; } + /// Itemized token usage breakdown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("tokenDetails")] + internal CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail[]? TokenDetails { get; set; } + + /// Total cost in nano-AI units for this request. + [JsonPropertyName("totalNanoAiu")] + public required double TotalNanoAiu { get; set; } } -/// Code selection attachment from an editor. -/// The selection variant of . -public sealed partial class AttachmentSelection : Attachment +/// Token usage breakdown for the compaction LLM call (aligned with assistant.usage format). +/// Nested data type for CompactionCompleteCompactionTokensUsed. +public sealed partial class CompactionCompleteCompactionTokensUsed { - /// - [JsonIgnore] - public override string Type => "selection"; + /// Whether the compaction's credit amount was reported for all, some, or none of its calls. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("aiCreditsStatus")] + public AiCreditsStatus? AiCreditsStatus { get; set; } - /// User-facing display name for the selection. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Cached input tokens reused in the compaction LLM call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cacheReadTokens")] + public long? CacheReadTokens { get; set; } - /// Absolute path to the file containing the selection. - [JsonPropertyName("filePath")] - public required string FilePath { get; set; } + /// Tokens written to prompt cache in the compaction LLM call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cacheWriteTokens")] + public long? CacheWriteTokens { get; set; } - /// Position range of the selection within the file. - [JsonPropertyName("selection")] - public required AttachmentSelectionDetails Selection { get; set; } + /// Per-request cost and usage data from the CAPI copilot_usage response field. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("copilotUsage")] + internal CompactionCompleteCompactionTokensUsedCopilotUsage? CopilotUsage { get; set; } - /// The selected text content. - [JsonPropertyName("text")] - public required string Text { get; set; } -} + /// Duration of the compaction LLM call in milliseconds. + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("duration")] + public TimeSpan? Duration { get; set; } -/// GitHub issue, pull request, or discussion reference. -/// The github_reference variant of . -public sealed partial class AttachmentGitHubReference : Attachment -{ - /// - [JsonIgnore] - public override string Type => "github_reference"; + /// Input tokens consumed by the compaction LLM call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("inputTokens")] + public long? InputTokens { get; set; } - /// Issue, pull request, or discussion number. - [JsonPropertyName("number")] - public required long Number { get; set; } + /// Model identifier used for the compaction LLM call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Type of GitHub reference. - [JsonPropertyName("referenceType")] - public required AttachmentGitHubReferenceType ReferenceType { get; set; } + /// Model display name captured for the compaction call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("modelDisplayName")] + public string? ModelDisplayName { get; set; } - /// Current state of the referenced item (e.g., open, closed, merged). - [JsonPropertyName("state")] - public required string State { get; set; } + /// Output tokens produced by the compaction LLM call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("outputTokens")] + public long? OutputTokens { get; set; } - /// Title of the referenced item. - [JsonPropertyName("title")] - public required string Title { get; set; } + /// Provider captured for the compaction call; absent when attribution is unknown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("provider")] + public ModelProviderRef? Provider { get; set; } - /// URL to the referenced item on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Number of model requests represented by this aggregated compaction usage. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestCount")] + public long? RequestCount { get; set; } } -/// Pointer to a GitHub repository. -/// Nested data type for GitHubRepoRef. -public sealed partial class GitHubRepoRef +/// Original request-level and effective conversation reasoning effort for a provider history boundary; the historical type name is retained for compatibility. +/// Nested data type for ResponsesReasoning. +public sealed partial class ResponsesReasoning { - /// Numeric GitHub repository id. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("id")] - public long? Id { get; set; } + /// Effective effort selected before this message, independent of the response-level reasoning field. + [JsonPropertyName("effort")] + public required string Effort { get; set; } - /// Repository name (without owner). - [JsonPropertyName("name")] - public required string Name { get; set; } + /// Original request-level effort, retained while replaying this conversation prefix. + [JsonPropertyName("initialEffort")] + public required string InitialEffort { get; set; } - /// Repository owner login (user or organization). - [JsonPropertyName("owner")] - public required string Owner { get; set; } + /// Provider model whose reasoning settings this boundary records. + [JsonPropertyName("model")] + public required string Model { get; set; } } -/// Pointer to a GitHub commit. -/// The github_commit variant of . -public sealed partial class AttachmentGitHubCommit : Attachment +/// Nested data type for PermissionRecoveryAttempt. +public sealed partial class PermissionRecoveryAttempt { - /// - [JsonIgnore] - public override string Type => "github_commit"; - - /// First line of the commit message. - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Full commit SHA. - [JsonPropertyName("oid")] - public required string Oid { get; set; } + /// Unique identifier for this attempt record. + [JsonPropertyName("attemptId")] + public required string AttemptId { get; set; } - /// Repository the commit belongs to. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } + /// How the runtime handled this attempt. + [JsonPropertyName("disposition")] + public required PermissionRecoveryAttemptDisposition Disposition { get; set; } - /// URL to the commit on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } -} + /// One-based position of this attempt in the episode. + [JsonPropertyName("ordinal")] + public required long Ordinal { get; set; } -/// Pointer to a GitHub release. -/// The github_release variant of . -public sealed partial class AttachmentGitHubRelease : Attachment -{ - /// - [JsonIgnore] - public override string Type => "github_release"; + /// Controlled permission request kind, such as shell, path, URL, or tool. + [JsonPropertyName("permissionKind")] + public required string PermissionKind { get; set; } - /// Human-readable release name. - [JsonPropertyName("name")] - public required string Name { get; set; } + /// Controlled reason for the attempt disposition. + [JsonPropertyName("reason")] + public required PermissionRecoveryAttemptReason Reason { get; set; } - /// Repository the release belongs to. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } + /// Relationship between this attempt and earlier attempts in the episode. + [JsonPropertyName("relation")] + public required PermissionRecoveryAttemptRelation Relation { get; set; } - /// Git tag the release is anchored to. - [JsonPropertyName("tagName")] - public required string TagName { get; set; } + /// SHA-256 fingerprint of normalized request data; raw permission arguments are not included. + [JsonPropertyName("requestFingerprint")] + public required string RequestFingerprint { get; set; } - /// URL to the release on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Tool-call identifier associated with this attempt, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } -/// Pointer to a GitHub Actions job. -/// The github_actions_job variant of . -public sealed partial class AttachmentGitHubActionsJob : Attachment +/// Authoritative snapshot of an Autopilot permission-recovery episode. +/// Nested data type for PermissionRecoveryData. +public sealed partial class PermissionRecoveryData { - /// - [JsonIgnore] - public override string Type => "github_actions_job"; - - /// Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("conclusion")] - public string? Conclusion { get; set; } - - /// Job id within the workflow run. - [JsonPropertyName("jobId")] - public required long JobId { get; set; } - - /// Display name of the job. - [JsonPropertyName("jobName")] - public required string JobName { get; set; } - - /// Repository the workflow run belongs to. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } + /// Ordered privacy-safe record of permission attempts and the successful alternative, when any. + [JsonPropertyName("attempts")] + public required PermissionRecoveryAttempt[] Attempts { get; set; } - /// URL to the job on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Stable identifier shared by every transition in this recovery episode. + [JsonPropertyName("episodeId")] + public required string EpisodeId { get; set; } - /// Display name of the workflow the job ran in. - [JsonPropertyName("workflowName")] - public required string WorkflowName { get; set; } -} + /// Maximum number of distinct autonomous permission attempts allowed before escalation. + [JsonPropertyName("maxAttempts")] + public required long MaxAttempts { get; set; } -/// Pointer to a GitHub repository. -/// The github_repository variant of . -public sealed partial class AttachmentGitHubRepository : Attachment -{ - /// - [JsonIgnore] - public override string Type => "github_repository"; + /// Policy selected from the current client's response capability; mode or client changes may update it during recovery. + [JsonPropertyName("onBlocked")] + public required PermissionRecoveryOnBlocked OnBlocked { get; set; } - /// Short description of the repository. + /// Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("ownerAgentId")] + public string? OwnerAgentId { get; set; } - /// Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. + /// Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ref")] - public string? Ref { get; set; } + [JsonPropertyName("ownerSessionId")] + public string? OwnerSessionId { get; set; } - /// Repository pointer. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } + /// Controlled reason for the latest episode transition. + [JsonPropertyName("reason")] + public required PermissionRecoveryReason Reason { get; set; } - /// URL to the repository on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Current lifecycle state of the recovery episode. + [JsonPropertyName("status")] + public required PermissionRecoveryStatus Status { get; set; } } -/// One side of a file diff (head or base). -/// Nested data type for AttachmentGitHubFileDiffSide. -public sealed partial class AttachmentGitHubFileDiffSide +/// Structured reason that the task cannot continue without intervention. +/// Nested data type for TaskBlocker. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class TaskBlocker { - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Category of intervention that blocked the task. + [JsonPropertyName("kind")] + public required TaskBlockerKind Kind { get; set; } - /// Git ref (branch, tag, or commit SHA) the file is read at. - [JsonPropertyName("ref")] - public required string Ref { get; set; } + /// Permission-recovery episode that produced this blocker. + [JsonPropertyName("permissionRecovery")] + public required PermissionRecoveryData PermissionRecovery { get; set; } - /// Repository the file lives in. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } + /// Controlled reason for the current blocked state. + [JsonPropertyName("reason")] + public required PermissionRecoveryReason Reason { get; set; } + + /// Whether a later user response or steering message can resume the task. + [JsonPropertyName("resumable")] + public required bool Resumable { get; set; } } -/// Pointer to a single-file diff. At least one of `head` and `base` must be present. -/// The github_file_diff variant of . -public sealed partial class AttachmentGitHubFileDiff : Attachment +/// Inclusive durable event range summarized by a completion receipt. +/// Nested data type for CompletionReceiptEventRange. +public sealed partial class CompletionReceiptEventRange { - /// - [JsonIgnore] - public override string Type => "github_file_diff"; + /// Identifier of the assistant turn-end event that ends the covered exchange. Always equals the receipt's sourceEventId, so either field is a valid join key. + [JsonPropertyName("endEventId")] + public required string EndEventId { get; set; } - /// File location on the base side of the diff. Absent for additions. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("base")] - public AttachmentGitHubFileDiffSide? Base { get; set; } + /// Identifier of the user message that starts the covered exchange. + [JsonPropertyName("startEventId")] + public required string StartEventId { get; set; } +} - /// File location on the head side of the diff. Absent for deletions. +/// Final structured tool completion in the covered event range. +/// Nested data type for CompletionReceiptFinalTool. +public sealed partial class CompletionReceiptFinalTool +{ + /// Process exit code from a structured shell result, when available. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("head")] - public AttachmentGitHubFileDiffSide? Head { get; set; } + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } - /// URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL). - [JsonPropertyName("url")] - public required string Url { get; set; } -} + /// Structured success or failure status from the tool completion event. + [JsonPropertyName("status")] + public required CompletionReceiptToolStatus Status { get; set; } -/// One side of a tree comparison (head or base). -/// Nested data type for AttachmentGitHubTreeComparisonSide. -public sealed partial class AttachmentGitHubTreeComparisonSide -{ - /// Repository the revision belongs to. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } + /// Unique identifier of the completed tool call. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } - /// Git revision (branch, tag, or commit SHA). - [JsonPropertyName("revision")] - public required string Revision { get; set; } + /// Tool name from the matching tool execution start event, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolName")] + public string? ToolName { get; set; } } -/// Pointer to a comparison between two git revisions. -/// The github_tree_comparison variant of . -public sealed partial class AttachmentGitHubTreeComparison : Attachment +/// Nested data type for FusionCritic. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class FusionCritic { - /// - [JsonIgnore] - public override string Type => "github_tree_comparison"; - - /// Base side of the comparison. - [JsonPropertyName("base")] - public required AttachmentGitHubTreeComparisonSide Base { get; set; } + /// Concrete model selected for this critic. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("model")] + public required string Model { get; set; } - /// Head side of the comparison. - [JsonPropertyName("head")] - public required AttachmentGitHubTreeComparisonSide Head { get; set; } + /// Unique execution phase identifier for this critic. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("phaseId")] + public required string PhaseId { get; set; } - /// URL to the comparison on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Explicit reasoning effort selected for this critic, if supplied. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } } -/// Generic GitHub URL reference. -/// The github_url variant of . -public sealed partial class AttachmentGitHubUrl : Attachment +/// Durable server recommendation for subsequent HydraFusion turns. +/// Nested data type for FusionFollowUpRecommendation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class FusionFollowUpRecommendation { - /// - [JsonIgnore] - public override string Type => "github_url"; + /// Recommended routing action for the next compaction turn. + [JsonPropertyName("compactionTurn")] + public required FusionFollowUpAction CompactionTurn { get; set; } - /// URL to the GitHub resource. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Recommended routing action for the next user-message turn. + [JsonPropertyName("userTurn")] + public required FusionFollowUpAction UserTurn { get; set; } } -/// Pointer to a file in a GitHub repository at a specific ref. -/// The github_file variant of . -public sealed partial class AttachmentGitHubFile : Attachment +/// Presentation-neutral phase planned for a HydraFusion turn. +/// Nested data type for FusionPhasePlanStep. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class FusionPhasePlanStep { - /// - [JsonIgnore] - public override string Type => "github_file"; - - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Whether the phase executes only when an earlier phase requests it. + [JsonPropertyName("conditional")] + public required bool Conditional { get; set; } - /// Git ref the file is read at (branch, tag, or commit SHA). - [JsonPropertyName("ref")] - public required string Ref { get; set; } + /// Kind of phase that may execute. + [JsonPropertyName("kind")] + public required FusionPhaseKind Kind { get; set; } - /// Repository the file lives in. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } + /// Semantic role assigned to the phase. + [JsonPropertyName("role")] + public required string Role { get; set; } - /// URL to the file on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Conversation scope in which the phase executes. + [JsonPropertyName("scope")] + public required FusionConversationScope Scope { get; set; } } -/// Pointer to a line range inside a file in a GitHub repository. -/// The github_snippet variant of . -public sealed partial class AttachmentGitHubSnippet : Attachment +/// Validated HydraFusion routing capability scores. +/// Nested data type for FusionScores. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class FusionScores { - /// - [JsonIgnore] - public override string Type => "github_snippet"; + /// Code-generation capability score returned by the authenticated router. + [JsonPropertyName("codeGen")] + public required double CodeGen { get; set; } - /// Line range the snippet covers. - [JsonPropertyName("lineRange")] - public required AttachmentFileLineRange LineRange { get; set; } + /// Debugging capability score returned by the authenticated router. + [JsonPropertyName("debugging")] + public required double Debugging { get; set; } - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Reasoning capability score returned by the authenticated router. + [JsonPropertyName("reasoning")] + public required double Reasoning { get; set; } - /// Git ref the file is read at (branch, tag, or commit SHA). - [JsonPropertyName("ref")] - public required string Ref { get; set; } + /// Tool-use capability score returned by the authenticated router. + [JsonPropertyName("toolUse")] + public required double ToolUse { get; set; } +} - /// Repository the file lives in. - [JsonPropertyName("repo")] - public required GitHubRepoRef Repo { get; set; } +/// Optional line range to scope the attachment to a specific section of the file. +/// Nested data type for AttachmentFileLineRange. +public sealed partial class AttachmentFileLineRange +{ + /// End line number (1-based, inclusive). + [JsonPropertyName("end")] + public required long End { get; set; } - /// URL to the snippet on GitHub (with line anchor). - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Start line number (1-based). + [JsonPropertyName("start")] + public required long Start { get; set; } } -/// Blob attachment with inline base64-encoded data. -/// The blob variant of . -public sealed partial class AttachmentBlob : Attachment +/// File attachment. +/// The file variant of . +public sealed partial class AttachmentFile : Attachment { /// [JsonIgnore] - public override string Type => "blob"; + public override string Type => "file"; /// Internal: content-addressed id of the session.binary_asset event holding this attachment's model-facing bytes (e.g. "sha256:..."). Absent externally. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -8743,1511 +9103,1975 @@ public sealed partial class AttachmentBlob : Attachment [JsonPropertyName("byteLength")] public long? ByteLength { get; set; } - /// Base64-encoded content. Present on input and for external consumers; replaced by an internal `assetId` reference in persisted events when interned to a content-addressed asset. - [Base64String] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("data")] - public string? Data { get; set; } - /// User-facing display name for the attachment. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } + public required string DisplayName { get; set; } - /// MIME type of the inline data. + /// Optional line range to scope the attachment to a specific section of the file. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("lineRange")] + public AttachmentFileLineRange? LineRange { get; set; } + + /// Internal: MIME type of the file's model-facing bytes (post-resize for images). Set when the file's bytes are interned to an asset. Absent externally. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + public string? MimeType { get; set; } /// Internal: why model-facing bytes are absent from persistence. Absent externally. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("omittedReason")] public OmittedBinaryOmittedReason? OmittedReason { get; set; } + + /// Absolute file path. + [JsonPropertyName("path")] + public required string Path { get; set; } + + /// Frozen rendered line this attachment contributed to the <tagged_files> prompt block (e.g. "* /path (123 lines)"). Captured at send time so resumed history reproduces the exact text the model saw, independent of later filesystem changes. Present only for attachments routed to <tagged_files> (mutually exclusive with assetId, which marks bytes sent natively). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("taggedFilesEntry")] + public string? TaggedFilesEntry { get; set; } } -/// 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 +/// Directory attachment. +/// The directory variant of . +public sealed partial class AttachmentDirectory : 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; } + public override string Type => "directory"; - /// ISO 8601 timestamp captured by the runtime when the push was accepted. - [JsonPropertyName("capturedAt")] - public required DateTimeOffset CapturedAt { get; set; } + /// User-facing display name for the attachment. + [JsonPropertyName("displayName")] + public required string DisplayName { 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; } + /// Absolute directory path. + [JsonPropertyName("path")] + public required string Path { get; set; } - /// Open canvas instance identifier when the push was bound to a canvas instance. + /// Frozen rendered line this attachment contributed to the <tagged_files> prompt block (e.g. "* /path (12 items)"). Captured at send time so resumed history reproduces the exact text the model saw, independent of later filesystem changes. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("instanceId")] - public string? InstanceId { get; set; } + [JsonPropertyName("taggedFilesEntry")] + public string? TaggedFilesEntry { get; set; } +} - /// Caller-supplied JSON payload. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("payload")] - public JsonElement? Payload { get; set; } +/// End position of the selection. +/// Nested data type for AttachmentSelectionDetailsEnd. +public sealed partial class AttachmentSelectionDetailsEnd +{ + /// End character offset within the line (0-based). + [JsonPropertyName("character")] + public required long Character { 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; } + /// End line number (0-based). + [JsonPropertyName("line")] + public required long Line { get; set; } } -/// A user message attachment — a file, directory, code selection, blob, GitHub reference, GitHub-anchored pointer, or extension-supplied context payload. -/// Polymorphic base type discriminated by type. -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AttachmentFile), "file")] -[JsonDerivedType(typeof(AttachmentDirectory), "directory")] -[JsonDerivedType(typeof(AttachmentSelection), "selection")] -[JsonDerivedType(typeof(AttachmentGitHubReference), "github_reference")] -[JsonDerivedType(typeof(AttachmentGitHubCommit), "github_commit")] -[JsonDerivedType(typeof(AttachmentGitHubRelease), "github_release")] -[JsonDerivedType(typeof(AttachmentGitHubActionsJob), "github_actions_job")] -[JsonDerivedType(typeof(AttachmentGitHubRepository), "github_repository")] -[JsonDerivedType(typeof(AttachmentGitHubFileDiff), "github_file_diff")] -[JsonDerivedType(typeof(AttachmentGitHubTreeComparison), "github_tree_comparison")] -[JsonDerivedType(typeof(AttachmentGitHubUrl), "github_url")] -[JsonDerivedType(typeof(AttachmentGitHubFile), "github_file")] -[JsonDerivedType(typeof(AttachmentGitHubSnippet), "github_snippet")] -[JsonDerivedType(typeof(AttachmentBlob), "blob")] -[JsonDerivedType(typeof(AttachmentExtensionContext), "extension_context")] -public partial class Attachment +/// Start position of the selection. +/// Nested data type for AttachmentSelectionDetailsStart. +public sealed partial class AttachmentSelectionDetailsStart { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + /// Start character offset within the line (0-based). + [JsonPropertyName("character")] + public required long Character { get; set; } + + /// Start line number (0-based). + [JsonPropertyName("line")] + public required long Line { get; set; } } +/// Position range of the selection within the file. +/// Nested data type for AttachmentSelectionDetails. +public sealed partial class AttachmentSelectionDetails +{ + /// End position of the selection. + [JsonPropertyName("end")] + public required AttachmentSelectionDetailsEnd End { get; set; } -/// Internal durable terminal request staged by a HydraFusion phase until an idempotent final commit selects it. -/// Nested data type for FusionStagedTerminal. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed partial class FusionStagedTerminal + /// Start position of the selection. + [JsonPropertyName("start")] + public required AttachmentSelectionDetailsStart Start { get; set; } +} + +/// Code selection attachment from an editor. +/// The selection variant of . +public sealed partial class AttachmentSelection : Attachment { - /// Gets or sets the arguments value. - [JsonPropertyName("arguments")] - public required string Arguments { get; set; } + /// + [JsonIgnore] + public override string Type => "selection"; - /// Gets or sets the assistantMessage value. - [JsonPropertyName("assistantMessage")] - public required JsonElement AssistantMessage { get; set; } + /// User-facing display name for the selection. + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } - /// Gets or sets the phaseId value. - [JsonPropertyName("phaseId")] - public required string PhaseId { get; set; } + /// Absolute path to the file containing the selection. + [JsonPropertyName("filePath")] + public required string FilePath { get; set; } - /// Gets or sets the toolCallId value. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } + /// Position range of the selection within the file. + [JsonPropertyName("selection")] + public required AttachmentSelectionDetails Selection { get; set; } - /// Gets or sets the toolName value. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } + /// The selected text content. + [JsonPropertyName("text")] + public required string Text { get; set; } } -/// Aggregate concrete-model usage for one HydraFusion phase. -/// Nested data type for FusionPhaseUsage. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class FusionPhaseUsage +/// GitHub issue, pull request, or discussion reference. +/// The github_reference variant of . +public sealed partial class AttachmentGitHubReference : Attachment { - /// Total cached input tokens reported for the phase. - [JsonPropertyName("cachedTokens")] - public required long CachedTokens { get; set; } + /// + [JsonIgnore] + public override string Type => "github_reference"; - /// Total tokens written to prompt cache during the phase. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cacheWriteTokens")] - public long? CacheWriteTokens { get; set; } + /// Issue, pull request, or discussion number. + [JsonPropertyName("number")] + public required long Number { get; set; } - /// Total input tokens consumed by the phase. - [JsonPropertyName("inputTokens")] - public required long InputTokens { get; set; } + /// Type of GitHub reference. + [JsonPropertyName("referenceType")] + public required AttachmentGitHubReferenceType ReferenceType { get; set; } - /// Total output tokens produced by the phase. - [JsonPropertyName("outputTokens")] - public required long OutputTokens { get; set; } + /// Current state of the referenced item (e.g., open, closed, merged). + [JsonPropertyName("state")] + public required string State { get; set; } - /// Number of concrete model requests made by the phase. - [JsonPropertyName("requestCount")] - public required long RequestCount { get; set; } + /// Title of the referenced item. + [JsonPropertyName("title")] + public required string Title { get; set; } - /// Total normalized AI-unit cost reported for the phase, in nano-AIU. - [JsonPropertyName("totalNanoAiu")] - public required double TotalNanoAiu { get; set; } + /// URL to the referenced item on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// A source that backs one or more cited spans in the assistant's response. -/// Nested data type for CitationSource. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class CitationSource +/// Pointer to a GitHub repository. +/// Nested data type for GitHubRepoRef. +public sealed partial class GitHubRepoRef { - /// Stable, turn-scoped identifier for this source, referenced by CitationReference.sourceId. + /// Numeric GitHub repository id. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("id")] - public required string Id { get; set; } + public long? Id { get; set; } - /// File path relative to the agent's workspace root, when the source is a file. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("path")] - public string? Path { get; set; } + /// Repository name (without owner). + [JsonPropertyName("name")] + public required string Name { get; set; } - /// The system that produced this citation. - [JsonPropertyName("provider")] - public required CitationProvider Provider { get; set; } + /// Repository owner login (user or organization). + [JsonPropertyName("owner")] + public required string Owner { get; set; } +} - /// Human-readable title of the source. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } +/// Pointer to a GitHub commit. +/// The github_commit variant of . +public sealed partial class AttachmentGitHubCommit : Attachment +{ + /// + [JsonIgnore] + public override string Type => "github_commit"; - /// URL of the source, when it is a web resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + /// First line of the commit message. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Full commit SHA. + [JsonPropertyName("oid")] + public required string Oid { get; set; } + + /// Repository the commit belongs to. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } + + /// URL to the commit on GitHub. [JsonPropertyName("url")] - public string? Url { get; set; } + public required string Url { get; set; } } -/// A character range within the source's text content. -/// The char variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class CitationLocationChar : CitationLocation +/// Pointer to a GitHub release. +/// The github_release variant of . +public sealed partial class AttachmentGitHubRelease : Attachment { /// [JsonIgnore] - public override string Type => "char"; + public override string Type => "github_release"; - /// End character offset within the source text (zero-based, exclusive). - [JsonPropertyName("endIndex")] - public required long EndIndex { get; set; } + /// Human-readable release name. + [JsonPropertyName("name")] + public required string Name { get; set; } - /// Start character offset within the source text (zero-based, inclusive). - [JsonPropertyName("startIndex")] - public required long StartIndex { get; set; } + /// Repository the release belongs to. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } + + /// Git tag the release is anchored to. + [JsonPropertyName("tagName")] + public required string TagName { get; set; } + + /// URL to the release on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// A page range within a paginated source document. -/// The page variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class CitationLocationPage : CitationLocation +/// Pointer to a GitHub Actions job. +/// The github_actions_job variant of . +public sealed partial class AttachmentGitHubActionsJob : Attachment { /// [JsonIgnore] - public override string Type => "page"; + public override string Type => "github_actions_job"; - /// Last page number of the cited range (inclusive). - [JsonPropertyName("endPage")] - public required long EndPage { get; set; } + /// Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("conclusion")] + public string? Conclusion { get; set; } - /// First page number of the cited range. - [JsonPropertyName("startPage")] - public required long StartPage { get; set; } + /// Job id within the workflow run. + [JsonPropertyName("jobId")] + public required long JobId { get; set; } + + /// Display name of the job. + [JsonPropertyName("jobName")] + public required string JobName { get; set; } + + /// Repository the workflow run belongs to. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } + + /// URL to the job on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } + + /// Display name of the workflow the job ran in. + [JsonPropertyName("workflowName")] + public required string WorkflowName { get; set; } } -/// A content-block range within a structured source document. -/// The block variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class CitationLocationBlock : CitationLocation +/// Pointer to a GitHub repository. +/// The github_repository variant of . +public sealed partial class AttachmentGitHubRepository : Attachment { /// [JsonIgnore] - public override string Type => "block"; + public override string Type => "github_repository"; - /// Index of the last content block of the cited range (zero-based, exclusive). - [JsonPropertyName("endBlock")] - public required long EndBlock { get; set; } + /// Short description of the repository. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Index of the first content block of the cited range (zero-based, inclusive). - [JsonPropertyName("startBlock")] - public required long StartBlock { get; set; } + /// Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ref")] + public string? Ref { get; set; } + + /// Repository pointer. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } + + /// URL to the repository on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// Location within a cited source (character, page, or content-block range) that supports a span. -/// Polymorphic base type discriminated by type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CitationLocationChar), "char")] -[JsonDerivedType(typeof(CitationLocationPage), "page")] -[JsonDerivedType(typeof(CitationLocationBlock), "block")] -public partial class CitationLocation +/// One side of a file diff (head or base). +/// Nested data type for AttachmentGitHubFileDiffSide. +public sealed partial class AttachmentGitHubFileDiffSide { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public required string Path { get; set; } + /// Git ref (branch, tag, or commit SHA) the file is read at. + [JsonPropertyName("ref")] + public required string Ref { get; set; } -/// A single citation occurrence linking a span of generated text to a supporting source. -/// Nested data type for CitationReference. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class CitationReference + /// Repository the file lives in. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } +} + +/// Pointer to a single-file diff. At least one of `head` and `base` must be present. +/// The github_file_diff variant of . +public sealed partial class AttachmentGitHubFileDiff : Attachment { - /// The exact text from the source that supports the cited span, when provided by the model. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("citedText")] - public string? CitedText { get; set; } + /// + [JsonIgnore] + public override string Type => "github_file_diff"; - /// Location within the source that supports the cited span, when the provider reports one. + /// File location on the base side of the diff. Absent for additions. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("location")] - public CitationLocation? Location { get; set; } + [JsonPropertyName("base")] + public AttachmentGitHubFileDiffSide? Base { get; set; } - /// Provider-native citation correlation data (e.g. Anthropic search_result_index / document_index), passed through opaquely for debugging and forward compatibility. + /// File location on the head side of the diff. Absent for deletions. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("providerMetadata")] - public JsonElement? ProviderMetadata { get; set; } + [JsonPropertyName("head")] + public AttachmentGitHubFileDiffSide? Head { get; set; } - /// Identifier of the CitationSource this reference points to (CitationSource.id). - [JsonPropertyName("sourceId")] - public required string SourceId { get; set; } + /// URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL). + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// A contiguous span of generated assistant text and the source references that support it. -/// Nested data type for CitationSpan. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class CitationSpan +/// One side of a tree comparison (head or base). +/// Nested data type for AttachmentGitHubTreeComparisonSide. +public sealed partial class AttachmentGitHubTreeComparisonSide { - /// End offset of the cited span within the final assistant message content (UTF-16 code units, zero-based, exclusive). - [JsonPropertyName("endIndex")] - public required long EndIndex { get; set; } - - /// The sources that support this span of generated text. - [JsonPropertyName("references")] - public required CitationReference[] References { get; set; } + /// Repository the revision belongs to. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } - /// Start offset of the cited span within the final assistant message content (UTF-16 code units, zero-based, inclusive). - [JsonPropertyName("startIndex")] - public required long StartIndex { get; set; } + /// Git revision (branch, tag, or commit SHA). + [JsonPropertyName("revision")] + public required string Revision { get; set; } } -/// Provider-agnostic citations linking spans of the assistant's response to their supporting sources. -/// Nested data type for Citations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class Citations +/// Pointer to a comparison between two git revisions. +/// The github_tree_comparison variant of . +public sealed partial class AttachmentGitHubTreeComparison : Attachment { - /// Deduplicated set of sources referenced by the citation spans. - [JsonPropertyName("sources")] - public required CitationSource[] Sources { get; set; } + /// + [JsonIgnore] + public override string Type => "github_tree_comparison"; - /// Spans of generated text annotated with the sources that support them. - [JsonPropertyName("spans")] - public required CitationSpan[] Spans { get; set; } + /// Base side of the comparison. + [JsonPropertyName("base")] + public required AttachmentGitHubTreeComparisonSide Base { get; set; } + + /// Head side of the comparison. + [JsonPropertyName("head")] + public required AttachmentGitHubTreeComparisonSide Head { get; set; } + + /// URL to the comparison on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// Experimental attribution linking an ordinary event to the HydraFusion turn, phase, and concrete source that produced it. -/// Nested data type for FusionAttribution. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class FusionAttribution +/// Generic GitHub URL reference. +/// The github_url variant of . +public sealed partial class AttachmentGitHubUrl : Attachment { - /// Idempotency identifier for the authoritative commit, when the event belongs to the selected output. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("commitId")] - public string? CommitId { get; set; } + /// + [JsonIgnore] + public override string Type => "github_url"; - /// Conversation scope in which the concrete phase executed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("conversationScope")] - public string? ConversationScope { get; set; } + /// URL to the GitHub resource. + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Stable identifier for the HydraFusion turn that produced the event. - [JsonPropertyName("fusionId")] - public required string FusionId { get; set; } +/// Pointer to a file in a GitHub repository at a specific ref. +/// The github_file variant of . +public sealed partial class AttachmentGitHubFile : Attachment +{ + /// + [JsonIgnore] + public override string Type => "github_file"; - /// Whether this model request consumed a user steering message rather than only internal Fusion work. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("hasUserSteering")] - public bool? HasUserSteering { get; set; } + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public required string Path { get; set; } - /// HydraFusion orchestration pattern selected for the turn. - [JsonPropertyName("pattern")] - public required string Pattern { get; set; } + /// Git ref the file is read at (branch, tag, or commit SHA). + [JsonPropertyName("ref")] + public required string Ref { get; set; } - /// Identifier of the concrete phase that produced the event. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("phaseId")] - public string? PhaseId { get; set; } + /// Repository the file lives in. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } - /// Kind of concrete phase that produced the event. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("phaseKind")] - public string? PhaseKind { get; set; } + /// URL to the file on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// HydraFusion routing policy used for the turn. - [JsonPropertyName("policy")] - public required string Policy { get; set; } +/// Pointer to a line range inside a file in a GitHub repository. +/// The github_snippet variant of . +public sealed partial class AttachmentGitHubSnippet : Attachment +{ + /// + [JsonIgnore] + public override string Type => "github_snippet"; - /// Semantic role assigned to the concrete phase. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("role")] - public string? Role { get; set; } + /// Line range the snippet covers. + [JsonPropertyName("lineRange")] + public required AttachmentFileLineRange LineRange { get; set; } - /// Concrete model that produced the attributed event. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("sourceModel")] - public string? SourceModel { get; set; } + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public required string Path { get; set; } - /// Phase whose output supplied the authoritative content, when different from the executing phase. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("sourcePhaseId")] - public string? SourcePhaseId { get; set; } + /// Git ref the file is read at (branch, tag, or commit SHA). + [JsonPropertyName("ref")] + public required string Ref { get; set; } - /// Synthetic HydraFusion model selected for the session. - [JsonPropertyName("syntheticModel")] - public required string SyntheticModel { get; set; } + /// Repository the file lives in. + [JsonPropertyName("repo")] + public required GitHubRepoRef Repo { get; set; } + + /// URL to the snippet on GitHub (with line anchor). + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// Neutral provider-tagged reasoning content blocks preserved verbatim for round-tripping. -/// Nested data type for AssistantMessageReasoningBlocks. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class AssistantMessageReasoningBlocks +/// Blob attachment with inline base64-encoded data. +/// The blob variant of . +public sealed partial class AttachmentBlob : Attachment { - /// Provider-native reasoning items or content blocks preserved verbatim, in order. A single response can carry several, and provider signatures or identifiers may depend on their exact content and ordering. + /// + [JsonIgnore] + public override string Type => "blob"; + + /// Internal: content-addressed id of the session.binary_asset event holding this attachment's model-facing bytes (e.g. "sha256:..."). Absent externally. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("blocks")] - public JsonElement[]? Blocks { get; set; } + [JsonPropertyName("assetId")] + public string? AssetId { get; set; } - /// Anthropic Messages assistant block ordering preserved when the legacy reasoning-only representation cannot reproduce it exactly. Thinking and text blocks remain verbatim; tool-use entries retain identity and a payload fingerprint when later signed reasoning depends on them, and are hydrated from the message's tool requests during replay. + /// Internal: decoded byte length of the attachment's model-facing bytes. Absent externally. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("orderedBlocks")] - public JsonElement[]? OrderedBlocks { get; set; } + [JsonPropertyName("byteLength")] + public long? ByteLength { get; set; } - /// Model provider that produced these reasoning blocks. - [JsonPropertyName("provider")] - public required string Provider { get; set; } -} - -/// Neutral provider-tagged server-side tool-use payload (tool search, advisor) for verbatim round-tripping. -/// Nested data type for AssistantMessageServerTools. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class AssistantMessageServerTools -{ - /// Advisor model identifier associated with the server-tool payload. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("advisorModel")] - public string? AdvisorModel { get; set; } - - /// Provider function-call namespaces keyed by function-call identifier. + /// Base64-encoded content. Present on input and for external consumers; replaced by an internal `assetId` reference in persisted events when interned to a content-addressed asset. + [Base64String] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("functionCallNamespaces")] - public IDictionary? FunctionCallNamespaces { get; set; } + [JsonPropertyName("data")] + public string? Data { get; set; } - /// Provider-native server-tool call and output items preserved verbatim for replay. + /// User-facing display name for the attachment. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("items")] - public JsonElement[]? Items { get; set; } + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } - /// Model provider that produced this server-tool payload. - [JsonPropertyName("provider")] - public required string Provider { get; set; } + /// MIME type of the inline data. + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } - /// Raw provider content blocks retained for verbatim round-tripping. + /// Internal: why model-facing bytes are absent from persistence. Absent externally. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("rawContentBlocks")] - public JsonElement[]? RawContentBlocks { get; set; } + [JsonPropertyName("omittedReason")] + public OmittedBinaryOmittedReason? OmittedReason { get; set; } } -/// Hosted program that requested this client tool call. -/// Nested data type for AssistantMessageToolRequestCaller. -public sealed partial class AssistantMessageToolRequestCaller +/// 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 { - /// Provider-assigned identifier for the hosted caller. - [JsonPropertyName("callerId")] - public required string CallerId { get; set; } - - /// Kind of hosted caller that requested the client tool call. - [JsonPropertyName("type")] - public required AssistantMessageToolRequestCallerType Type { get; set; } -} + /// + [JsonIgnore] + public override string Type => "extension_context"; -/// A tool invocation request from the assistant. -/// Nested data type for AssistantMessageToolRequest. -public sealed partial class AssistantMessageToolRequest -{ - /// Arguments to pass to the tool, format depends on the tool. + /// Provider-local canvas identifier when the push was bound to a canvas instance. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("arguments")] - public JsonElement? Arguments { get; set; } + [JsonPropertyName("canvasId")] + public string? CanvasId { get; set; } - /// Hosted program that requested this client tool call. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("caller")] - public AssistantMessageToolRequestCaller? Caller { get; set; } + /// ISO 8601 timestamp captured by the runtime when the push was accepted. + [JsonPropertyName("capturedAt")] + public required DateTimeOffset CapturedAt { get; set; } - /// Resolved intention summary describing what this specific call does. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("intentionSummary")] - public string? IntentionSummary { 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; } - /// Name of the MCP server hosting this tool, when the tool is an MCP tool. + /// Open canvas instance identifier when the push was bound to a canvas instance. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mcpServerName")] - public string? McpServerName { get; set; } + [JsonPropertyName("instanceId")] + public string? InstanceId { get; set; } - /// Original tool name on the MCP server, when the tool is an MCP tool. + /// Caller-supplied JSON payload. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mcpToolName")] - public string? McpToolName { get; set; } - - /// Name of the tool being invoked. - [JsonPropertyName("name")] - public required string Name { get; set; } - - /// Unique identifier for this tool call. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } + [JsonPropertyName("payload")] + public JsonElement? Payload { get; set; } - /// Human-readable display title for the tool. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("toolTitle")] - public string? ToolTitle { 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; } +} - /// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] +/// A user message attachment — a file, directory, code selection, blob, GitHub reference, GitHub-anchored pointer, or extension-supplied context payload. +/// Polymorphic base type discriminated by type. +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AttachmentFile), "file")] +[JsonDerivedType(typeof(AttachmentDirectory), "directory")] +[JsonDerivedType(typeof(AttachmentSelection), "selection")] +[JsonDerivedType(typeof(AttachmentGitHubReference), "github_reference")] +[JsonDerivedType(typeof(AttachmentGitHubCommit), "github_commit")] +[JsonDerivedType(typeof(AttachmentGitHubRelease), "github_release")] +[JsonDerivedType(typeof(AttachmentGitHubActionsJob), "github_actions_job")] +[JsonDerivedType(typeof(AttachmentGitHubRepository), "github_repository")] +[JsonDerivedType(typeof(AttachmentGitHubFileDiff), "github_file_diff")] +[JsonDerivedType(typeof(AttachmentGitHubTreeComparison), "github_tree_comparison")] +[JsonDerivedType(typeof(AttachmentGitHubUrl), "github_url")] +[JsonDerivedType(typeof(AttachmentGitHubFile), "github_file")] +[JsonDerivedType(typeof(AttachmentGitHubSnippet), "github_snippet")] +[JsonDerivedType(typeof(AttachmentBlob), "blob")] +[JsonDerivedType(typeof(AttachmentExtensionContext), "extension_context")] +public partial class Attachment +{ + /// The type discriminator. [JsonPropertyName("type")] - public AssistantMessageToolRequestType? Type { get; set; } + public virtual string Type { get; set; } = string.Empty; } -/// Token usage detail for a single billing category. -/// Nested data type for AssistantUsageCopilotUsageTokenDetail. -public sealed partial class AssistantUsageCopilotUsageTokenDetail + +/// Internal durable terminal request staged by a HydraFusion phase until an idempotent final commit selects it. +/// Nested data type for FusionStagedTerminal. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed partial class FusionStagedTerminal { - /// Number of tokens in this billing batch. - [JsonPropertyName("batchSize")] - public required long BatchSize { get; set; } + /// Gets or sets the arguments value. + [JsonPropertyName("arguments")] + public required string Arguments { get; set; } - /// Cost per batch of tokens. - [JsonPropertyName("costPerBatch")] - public required long CostPerBatch { get; set; } + /// Gets or sets the assistantMessage value. + [JsonPropertyName("assistantMessage")] + public required JsonElement AssistantMessage { get; set; } - /// Model responsible for this billing entry. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Gets or sets the phaseId value. + [JsonPropertyName("phaseId")] + public required string PhaseId { get; set; } - /// Total token count for this entry. - [JsonPropertyName("tokenCount")] - public required long TokenCount { get; set; } + /// Gets or sets the toolCallId value. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } - /// Token category (e.g., "input", "output"). - [JsonPropertyName("tokenType")] - public required string TokenType { get; set; } + /// Gets or sets the toolName value. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } -/// Per-request cost and usage data from the CAPI copilot_usage response field. -/// Nested data type for AssistantUsageCopilotUsage. -public sealed partial class AssistantUsageCopilotUsage +/// Aggregate concrete-model usage for one HydraFusion phase. +/// Nested data type for FusionPhaseUsage. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class FusionPhaseUsage { - /// Default billing model for token details that do not identify their own model. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Total cached input tokens reported for the phase. + [JsonPropertyName("cachedTokens")] + public required long CachedTokens { get; set; } - /// Itemized token usage breakdown. + /// Total tokens written to prompt cache during the phase. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("tokenDetails")] - internal AssistantUsageCopilotUsageTokenDetail[]? TokenDetails { get; set; } + [JsonPropertyName("cacheWriteTokens")] + public long? CacheWriteTokens { get; set; } - /// Total cost in nano-AI units for this request. + /// Total input tokens consumed by the phase. + [JsonPropertyName("inputTokens")] + public required long InputTokens { get; set; } + + /// Total output tokens produced by the phase. + [JsonPropertyName("outputTokens")] + public required long OutputTokens { get; set; } + + /// Number of concrete model requests made by the phase. + [JsonPropertyName("requestCount")] + public required long RequestCount { get; set; } + + /// Total normalized AI-unit cost reported for the phase, in nano-AIU. [JsonPropertyName("totalNanoAiu")] public required double TotalNanoAiu { get; set; } } -/// Internal per-quota snapshot for assistant usage, including entitlement, consumed requests, overage, reset date, and remaining quota. -/// Nested data type for AssistantUsageQuotaSnapshot. -internal sealed partial class AssistantUsageQuotaSnapshot +/// A source that backs one or more cited spans in the assistant's response. +/// Nested data type for CitationSource. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class CitationSource { - /// Total requests allowed by the entitlement. - [JsonInclude] - [JsonPropertyName("entitlementRequests")] - internal required long EntitlementRequests { get; set; } + /// Stable, turn-scoped identifier for this source, referenced by CitationReference.sourceId. + [JsonPropertyName("id")] + public required string Id { get; set; } - /// Whether the user currently has quota available for use. + /// File path relative to the agent's workspace root, when the source is a file. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("hasQuota")] - internal bool? HasQuota { get; set; } - - /// Whether the user has an unlimited usage entitlement. - [JsonInclude] - [JsonPropertyName("isUnlimitedEntitlement")] - internal required bool IsUnlimitedEntitlement { get; set; } + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Number of additional usage requests made this period. - [JsonInclude] - [JsonPropertyName("overage")] - internal required double Overage { get; set; } + /// The system that produced this citation. + [JsonPropertyName("provider")] + public required CitationProvider Provider { get; set; } - /// Whether additional usage is allowed when quota is exhausted. - [JsonInclude] - [JsonPropertyName("overageAllowedWithExhaustedQuota")] - internal required bool OverageAllowedWithExhaustedQuota { get; set; } + /// Human-readable title of the source. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("title")] + public string? Title { get; set; } - /// Pay-as-you-go additional-usage budget cap in AI credits (1 credit = $0.01); present only when CAPI emits a finite value. + /// URL of the source, when it is a web resource. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("overageEntitlement")] - internal double? OverageEntitlement { get; set; } - - /// Percentage of quota remaining (0 to 100). - [JsonInclude] - [JsonPropertyName("remainingPercentage")] - internal required double RemainingPercentage { get; set; } - - /// Date when the quota resets. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("resetDate")] - internal DateTimeOffset? ResetDate { get; set; } - - /// Whether this snapshot uses token-based billing (AI-credits allocation). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("tokenBasedBilling")] - internal bool? TokenBasedBilling { get; set; } - - /// Whether usage is still permitted after quota exhaustion. - [JsonInclude] - [JsonPropertyName("usageAllowedWithExhaustedQuota")] - internal required bool UsageAllowedWithExhaustedQuota { get; set; } - - /// Number of requests already consumed. - [JsonInclude] - [JsonPropertyName("usedRequests")] - internal required long UsedRequests { get; set; } + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// Content-free structural summary of the failing request for diagnosing malformed 4xx calls. -/// Nested data type for ModelCallFailureRequestFingerprint. -public sealed partial class ModelCallFailureRequestFingerprint +/// A character range within the source's text content. +/// The char variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class CitationLocationChar : CitationLocation { - /// Total number of image content parts. - [JsonPropertyName("imagePartCount")] - public required long ImagePartCount { get; set; } - - /// Image parts whose media type cannot be determined (rejected by strict providers). - [JsonPropertyName("imagePartsMissingMediaType")] - public required long ImagePartsMissingMediaType { get; set; } + /// + [JsonIgnore] + public override string Type => "char"; - /// Role of the final message in the request. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("lastMessageRole")] - public string? LastMessageRole { get; set; } + /// End character offset within the source text (zero-based, exclusive). + [JsonPropertyName("endIndex")] + public required long EndIndex { get; set; } - /// Total number of messages in the request. - [JsonPropertyName("messageCount")] - public required long MessageCount { get; set; } + /// Start character offset within the source text (zero-based, inclusive). + [JsonPropertyName("startIndex")] + public required long StartIndex { get; set; } +} - /// Tool calls whose name is missing or empty (rejected by strict providers). - [JsonPropertyName("namelessToolCallCount")] - public required long NamelessToolCallCount { get; set; } +/// A page range within a paginated source document. +/// The page variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class CitationLocationPage : CitationLocation +{ + /// + [JsonIgnore] + public override string Type => "page"; - /// Total number of tool calls across assistant messages. - [JsonPropertyName("toolCallCount")] - public required long ToolCallCount { get; set; } + /// Last page number of the cited range (inclusive). + [JsonPropertyName("endPage")] + public required long EndPage { get; set; } - /// Number of "tool" result messages in the request. - [JsonPropertyName("toolResultMessageCount")] - public required long ToolResultMessageCount { get; set; } + /// First page number of the cited range. + [JsonPropertyName("startPage")] + public required long StartPage { get; set; } } -/// Shell-aware path hints for a shell tool's command, captured at start time so consumers can snapshot a file's pre-image before the tool runs. -/// Nested data type for ToolExecutionStartShellToolInfo. -public sealed partial class ToolExecutionStartShellToolInfo +/// A content-block range within a structured source document. +/// The block variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class CitationLocationBlock : CitationLocation { - /// The command with a redundant leading `cd` into the working directory removed, present only when there was one to remove. Computed with the same routine the shell driver applies before spawning, so a surface that renders this shows the text that actually runs. Consumers that display it should keep the original tool arguments available on demand. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("displayCommand")] - public string? DisplayCommand { get; set; } + /// + [JsonIgnore] + public override string Type => "block"; - /// Whether the command includes a file write redirection (e.g., > or >>). - [JsonPropertyName("hasWriteFileRedirection")] - public required bool HasWriteFileRedirection { get; set; } + /// Index of the last content block of the cited range (zero-based, exclusive). + [JsonPropertyName("endBlock")] + public required long EndBlock { get; set; } - /// File paths the command may read or write, derived from the command at start time. Produced by the same shell-aware extractor as PermissionRequestShell.possiblePaths, so it is present even when the command is auto-approved and no permission request fires. - [JsonPropertyName("possiblePaths")] - public required string[] PossiblePaths { get; set; } + /// Index of the first content block of the cited range (zero-based, inclusive). + [JsonPropertyName("startBlock")] + public required long StartBlock { get; set; } } -/// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`. -/// Nested data type for ToolExecutionStartToolDescriptionMetaUI. -public sealed partial class ToolExecutionStartToolDescriptionMetaUI +/// Location within a cited source (character, page, or content-block range) that supports a span. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CitationLocationChar), "char")] +[JsonDerivedType(typeof(CitationLocationPage), "page")] +[JsonDerivedType(typeof(CitationLocationBlock), "block")] +public partial class CitationLocation { - /// URI of the UI resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resourceUri")] - public string? ResourceUri { get; set; } - - /// Who can access this tool. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("visibility")] - public ToolExecutionStartToolDescriptionMetaUIVisibility[]? Visibility { get; set; } + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// MCP Apps metadata for UI resource association. -/// Nested data type for ToolExecutionStartToolDescriptionMeta. -public sealed partial class ToolExecutionStartToolDescriptionMeta + +/// A single citation occurrence linking a span of generated text to a supporting source. +/// Nested data type for CitationReference. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class CitationReference { - /// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`. + /// The exact text from the source that supports the cited span, when provided by the model. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ui")] - public ToolExecutionStartToolDescriptionMetaUI? Ui { get; set; } -} + [JsonPropertyName("citedText")] + public string? CitedText { get; set; } -/// Tool definition metadata, present for MCP tools with MCP Apps support. -/// Nested data type for ToolExecutionStartToolDescription. -public sealed partial class ToolExecutionStartToolDescription -{ - /// MCP Apps metadata for UI resource association. + /// Location within the source that supports the cited span, when the provider reports one. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("_meta")] - public ToolExecutionStartToolDescriptionMeta? Meta { get; set; } + [JsonPropertyName("location")] + public CitationLocation? Location { get; set; } - /// Tool description. + /// Provider-native citation correlation data (e.g. Anthropic search_result_index / document_index), passed through opaquely for debugging and forward compatibility. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("providerMetadata")] + public JsonElement? ProviderMetadata { get; set; } - /// Tool name. - [JsonPropertyName("name")] - public required string Name { get; set; } + /// Identifier of the CitationSource this reference points to (CitationSource.id). + [JsonPropertyName("sourceId")] + public required string SourceId { get; set; } } -/// Error details when the tool execution failed. -/// Nested data type for ToolExecutionCompleteError. -public sealed partial class ToolExecutionCompleteError +/// A contiguous span of generated assistant text and the source references that support it. +/// Nested data type for CitationSpan. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class CitationSpan { - /// Machine-readable error code. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("code")] - public string? Code { get; set; } + /// End offset of the cited span within the final assistant message content (UTF-16 code units, zero-based, exclusive). + [JsonPropertyName("endIndex")] + public required long EndIndex { get; set; } - /// Human-readable error message. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// The sources that support this span of generated text. + [JsonPropertyName("references")] + public required CitationReference[] References { get; set; } - /// What the user must do to recover, when the runtime knows of an action. Set on sandbox policy denials, where `message` names the rule that blocked the call but never the client affordance that relaxes it. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("remediation")] - public RemediationAction? Remediation { get; set; } + /// Start offset of the cited span within the final assistant message content (UTF-16 code units, zero-based, inclusive). + [JsonPropertyName("startIndex")] + public required long StartIndex { get; set; } } -/// A file mutation that was actually committed by a built-in file editing tool. -/// Nested data type for ToolExecutionCompleteFileEdit. +/// Provider-agnostic citations linking spans of the assistant's response to their supporting sources. +/// Nested data type for Citations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class ToolExecutionCompleteFileEdit +public sealed partial class Citations { - /// Kind of mutation committed at this path. - [JsonPropertyName("kind")] - public required ToolExecutionCompleteFileEditKind Kind { get; set; } + /// Deduplicated set of sources referenced by the citation spans. + [JsonPropertyName("sources")] + public required CitationSource[] Sources { get; set; } - /// Absolute path in the session filesystem namespace. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Spans of generated text annotated with the sources that support them. + [JsonPropertyName("spans")] + public required CitationSpan[] Spans { get; set; } } -/// Binary result returned by a tool for the model. -/// Nested data type for PersistedBinaryImage. -public sealed partial class PersistedBinaryImage +/// Experimental attribution linking an ordinary event to the HydraFusion turn, phase, and concrete source that produced it. +/// Nested data type for FusionAttribution. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class FusionAttribution { - /// Base64-encoded binary data. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Idempotency identifier for the authoritative commit, when the event belongs to the selected output. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("commitId")] + public string? CommitId { get; set; } - /// Human-readable description of the binary data. + /// Conversation scope in which the concrete phase executed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("conversationScope")] + public string? ConversationScope { get; set; } - /// Optional metadata from the producing tool. + /// Stable identifier for the HydraFusion turn that produced the event. + [JsonPropertyName("fusionId")] + public required string FusionId { get; set; } + + /// Whether this model request consumed a user steering message rather than only internal Fusion work. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } + [JsonPropertyName("hasUserSteering")] + public bool? HasUserSteering { get; set; } - /// MIME type of the binary data. - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// HydraFusion orchestration pattern selected for the turn. + [JsonPropertyName("pattern")] + public required string Pattern { get; set; } - /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. - [JsonPropertyName("type")] - public required PersistedBinaryImageType Type { get; set; } -} - -/// A binary result whose data was omitted from persistence due to the inline size limit. -/// Nested data type for OmittedBinaryResult. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class OmittedBinaryResult -{ - /// Decoded byte length of the omitted binary data. - [JsonPropertyName("byteLength")] - public required long ByteLength { get; set; } + /// Identifier of the concrete phase that produced the event. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("phaseId")] + public string? PhaseId { get; set; } - /// Human-readable description of the binary data. + /// Kind of concrete phase that produced the event. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("phaseKind")] + public string? PhaseKind { get; set; } - /// Optional metadata from the producing tool. + /// HydraFusion routing policy used for the turn. + [JsonPropertyName("policy")] + public required string Policy { get; set; } + + /// Semantic role assigned to the concrete phase. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } + [JsonPropertyName("role")] + public string? Role { get; set; } - /// MIME type of the omitted binary data. - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// Concrete model that produced the attributed event. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("sourceModel")] + public string? SourceModel { get; set; } - /// Why the binary data is absent: it exceeded the inline size limit, or its asset was unavailable. - [JsonPropertyName("omittedReason")] - public required OmittedBinaryOmittedReason OmittedReason { get; set; } + /// Phase whose output supplied the authoritative content, when different from the executing phase. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("sourcePhaseId")] + public string? SourcePhaseId { get; set; } - /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. - [JsonPropertyName("type")] - public required OmittedBinaryType Type { get; set; } + /// Synthetic HydraFusion model selected for the session. + [JsonPropertyName("syntheticModel")] + public required string SyntheticModel { get; set; } } -/// A reference to binary data persisted once on a session.binary_asset event and shared by id. -/// Nested data type for BinaryAssetReference. +/// Neutral provider-tagged reasoning content blocks preserved verbatim for round-tripping. +/// Nested data type for AssistantMessageReasoningBlocks. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class BinaryAssetReference +public sealed partial class AssistantMessageReasoningBlocks { - /// Content-addressed id of the session.binary_asset event that holds this binary's bytes (e.g. "sha256:..."). - [JsonPropertyName("assetId")] - public required string AssetId { get; set; } + /// Provider-native reasoning items or content blocks preserved verbatim, in order. A single response can carry several, and provider signatures or identifiers may depend on their exact content and ordering. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("blocks")] + public JsonElement[]? Blocks { get; set; } - /// Decoded byte length of the referenced binary data. - [JsonPropertyName("byteLength")] - public required long ByteLength { get; set; } + /// Anthropic Messages assistant block ordering preserved when the legacy reasoning-only representation cannot reproduce it exactly. Thinking and text blocks remain verbatim; tool-use entries retain identity and a payload fingerprint when later signed reasoning depends on them, and are hydrated from the message's tool requests during replay. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("orderedBlocks")] + public JsonElement[]? OrderedBlocks { get; set; } - /// Human-readable description of the binary data. + /// Model provider that produced these reasoning blocks. + [JsonPropertyName("provider")] + public required string Provider { get; set; } +} + +/// Neutral provider-tagged server-side tool-use payload (tool search, advisor) for verbatim round-tripping. +/// Nested data type for AssistantMessageServerTools. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class AssistantMessageServerTools +{ + /// Advisor model identifier associated with the server-tool payload. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("advisorModel")] + public string? AdvisorModel { get; set; } - /// Optional metadata from the producing tool. + /// Provider function-call namespaces keyed by function-call identifier. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } + [JsonPropertyName("functionCallNamespaces")] + public IDictionary? FunctionCallNamespaces { get; set; } - /// MIME type of the referenced binary data. - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// Provider-native server-tool call and output items preserved verbatim for replay. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("items")] + public JsonElement[]? Items { get; set; } - /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. - [JsonPropertyName("type")] - public required BinaryAssetReferenceType Type { get; set; } + /// Model provider that produced this server-tool payload. + [JsonPropertyName("provider")] + public required string Provider { get; set; } + + /// Raw provider content blocks retained for verbatim round-tripping. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("rawContentBlocks")] + public JsonElement[]? RawContentBlocks { get; set; } } -/// A model-facing binary result as persisted: full inline data, a size-omitted marker, or a deduplicated asset reference. -/// JSON union data type for PersistedBinaryResult. -[JsonConverter(typeof(Converter))] -public sealed partial class PersistedBinaryResult +/// Hosted program that requested this client tool call. +/// Nested data type for AssistantMessageToolRequestCaller. +public sealed partial class AssistantMessageToolRequestCaller { - /// Gets the value when this instance contains . - public PersistedBinaryImage? PersistedBinaryImage { get; } + /// Provider-assigned identifier for the hosted caller. + [JsonPropertyName("callerId")] + public required string CallerId { get; set; } - /// Gets the value when this instance contains . - public OmittedBinaryResult? OmittedBinaryResult { get; } + /// Kind of hosted caller that requested the client tool call. + [JsonPropertyName("type")] + public required AssistantMessageToolRequestCallerType Type { get; set; } +} - /// Gets the value when this instance contains . - public BinaryAssetReference? BinaryAssetReference { get; } +/// A tool invocation request from the assistant. +/// Nested data type for AssistantMessageToolRequest. +public sealed partial class AssistantMessageToolRequest +{ + /// Arguments to pass to the tool, format depends on the tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("arguments")] + public JsonElement? Arguments { get; set; } - /// Initializes a new instance of the class from . - public PersistedBinaryResult(PersistedBinaryImage value) - { - ArgumentNullException.ThrowIfNull(value); - PersistedBinaryImage = value; - } + /// Hosted program that requested this client tool call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("caller")] + public AssistantMessageToolRequestCaller? Caller { get; set; } - /// Converts to . - public static implicit operator PersistedBinaryResult(PersistedBinaryImage value) => new(value); + /// Resolved intention summary describing what this specific call does. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("intentionSummary")] + public string? IntentionSummary { get; set; } - /// Initializes a new instance of the class from . - public PersistedBinaryResult(OmittedBinaryResult value) - { - ArgumentNullException.ThrowIfNull(value); - OmittedBinaryResult = value; - } + /// Name of the MCP server hosting this tool, when the tool is an MCP tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mcpServerName")] + public string? McpServerName { get; set; } - /// Converts to . - public static implicit operator PersistedBinaryResult(OmittedBinaryResult value) => new(value); + /// Original tool name on the MCP server, when the tool is an MCP tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mcpToolName")] + public string? McpToolName { get; set; } - /// Initializes a new instance of the class from . - public PersistedBinaryResult(BinaryAssetReference value) - { - ArgumentNullException.ThrowIfNull(value); - BinaryAssetReference = value; - } + /// Name of the tool being invoked. + [JsonPropertyName("name")] + public required string Name { get; set; } - /// Converts to . - public static implicit operator PersistedBinaryResult(BinaryAssetReference value) => new(value); + /// Unique identifier for this tool call. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override PersistedBinaryResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) - { - throw new JsonException("Expected JSON object for PersistedBinaryResult."); - } + /// Human-readable display title for the tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("toolTitle")] + public string? ToolTitle { get; set; } - using var document = JsonDocument.ParseValue(ref reader); - var element = document.RootElement; - if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("data", out _) && !element.TryGetProperty("assetId", out _) && !element.TryGetProperty("byteLength", out _) && !element.TryGetProperty("omittedReason", out _)) - { - var persistedBinaryImage = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.PersistedBinaryImage); - return persistedBinaryImage is null ? throw new JsonException("Expected PersistedBinaryImage value.") : new PersistedBinaryResult(persistedBinaryImage); - } - if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("omittedReason", out _) && !element.TryGetProperty("assetId", out _) && !element.TryGetProperty("data", out _)) - { - var omittedBinaryResult = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.OmittedBinaryResult); - return omittedBinaryResult is null ? throw new JsonException("Expected OmittedBinaryResult value.") : new PersistedBinaryResult(omittedBinaryResult); - } - if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("assetId", out _) && !element.TryGetProperty("data", out _) && !element.TryGetProperty("omittedReason", out _)) - { - var binaryAssetReference = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.BinaryAssetReference); - return binaryAssetReference is null ? throw new JsonException("Expected BinaryAssetReference value.") : new PersistedBinaryResult(binaryAssetReference); - } + /// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("type")] + public AssistantMessageToolRequestType? Type { get; set; } +} - throw new JsonException("JSON value did not match any PersistedBinaryResult variant."); - } +/// Ordered accounting identity assigned under the source session's emission lock. +/// Nested data type for UsageAccountingIdentity. +public sealed partial class UsageAccountingIdentity +{ + /// Monotonically increasing sequence within the source session. + [JsonPropertyName("sequence")] + public required long Sequence { get; set; } - /// - public override void Write(Utf8JsonWriter writer, PersistedBinaryResult value, JsonSerializerOptions options) - { - if (value.PersistedBinaryImage is { } persistedBinaryImage) - { - JsonSerializer.Serialize(writer, persistedBinaryImage, SessionEventsJsonContext.Default.PersistedBinaryImage); - return; - } - if (value.OmittedBinaryResult is { } omittedBinaryResult) - { - JsonSerializer.Serialize(writer, omittedBinaryResult, SessionEventsJsonContext.Default.OmittedBinaryResult); - return; - } - if (value.BinaryAssetReference is { } binaryAssetReference) - { - JsonSerializer.Serialize(writer, binaryAssetReference, SessionEventsJsonContext.Default.BinaryAssetReference); - return; - } + /// Session that assigned this accounting sequence. + [JsonPropertyName("sourceSessionId")] + public required string SourceSessionId { get; set; } - throw new JsonException("No PersistedBinaryResult variant value is set."); - } - } + /// Existing API call identifier, or a runtime-generated identity when none was supplied. + [JsonPropertyName("usageId")] + public required string UsageId { get; set; } } -/// A source supplied by a tool that should be made available to the model as citable content. -/// Nested data type for CitableSource. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class CitableSource -{ - /// The source text made available to the model as citable content. - [JsonPropertyName("content")] - public required string Content { get; set; } +/// Token usage detail for a single billing category. +/// Nested data type for AssistantUsageCopilotUsageTokenDetail. +public sealed partial class AssistantUsageCopilotUsageTokenDetail +{ + /// Number of tokens in this billing batch. + [JsonPropertyName("batchSize")] + public required long BatchSize { get; set; } - /// Stable identifier for this source within the tool result. Used for deduplication and may be used by future provider integrations to correlate response citations back to the originating source. - [JsonPropertyName("id")] - public required string Id { get; set; } + /// Cost per batch of tokens. + [JsonPropertyName("costPerBatch")] + public required long CostPerBatch { get; set; } - /// File path relative to the agent's workspace root, when the source is a file. + /// Model responsible for this billing entry. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("path")] - public string? Path { get; set; } + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Human-readable title of the source. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Total token count for this entry. + [JsonPropertyName("tokenCount")] + public required long TokenCount { get; set; } - /// URL of the source, when it is a web resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("url")] - public string? Url { get; set; } + /// Token category (e.g., "input", "output"). + [JsonPropertyName("tokenType")] + public required string TokenType { get; set; } } -/// Plain text content block. -/// The text variant of . -public sealed partial class ToolExecutionCompleteContentText : ToolExecutionCompleteContent +/// Per-request cost and usage data from the CAPI copilot_usage response field. +/// Nested data type for AssistantUsageCopilotUsage. +public sealed partial class AssistantUsageCopilotUsage { - /// - [JsonIgnore] - public override string Type => "text"; + /// Default billing model for token details that do not identify their own model. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("model")] + public string? Model { get; set; } - /// The text content. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Itemized token usage breakdown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("tokenDetails")] + internal AssistantUsageCopilotUsageTokenDetail[]? TokenDetails { get; set; } + + /// Total cost in nano-AI units for this request. + [JsonPropertyName("totalNanoAiu")] + public required double TotalNanoAiu { get; set; } } -/// Deprecated for shell command exit metadata. Use ToolExecutionCompleteContentShellExit instead. -/// The terminal variant of . -[EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER -[Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else -[Obsolete("This member is deprecated and will be removed in a future version.")] -#endif -public sealed partial class ToolExecutionCompleteContentTerminal : ToolExecutionCompleteContent +/// Internal per-quota snapshot for assistant usage, including entitlement, consumed requests, overage, reset date, and remaining quota. +/// Nested data type for AssistantUsageQuotaSnapshot. +internal sealed partial class AssistantUsageQuotaSnapshot { - /// - [JsonIgnore] - public override string Type => "terminal"; + /// Total requests allowed by the entitlement. + [JsonInclude] + [JsonPropertyName("entitlementRequests")] + internal required long EntitlementRequests { get; set; } - /// Working directory where the command was executed. + /// Whether the user currently has quota available for use. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + [JsonInclude] + [JsonPropertyName("hasQuota")] + internal bool? HasQuota { get; set; } - /// Process exit code, if the command has completed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } + /// Whether the user has an unlimited usage entitlement. + [JsonInclude] + [JsonPropertyName("isUnlimitedEntitlement")] + internal required bool IsUnlimitedEntitlement { get; set; } - /// Terminal/shell output text. - [JsonPropertyName("text")] - public required string Text { get; set; } -} + /// Number of additional usage requests made this period. + [JsonInclude] + [JsonPropertyName("overage")] + internal required double Overage { get; set; } -/// Shell command exit metadata with optional output preview. -/// The shell_exit variant of . -public sealed partial class ToolExecutionCompleteContentShellExit : ToolExecutionCompleteContent -{ - /// - [JsonIgnore] - public override string Type => "shell_exit"; + /// Whether additional usage is allowed when quota is exhausted. + [JsonInclude] + [JsonPropertyName("overageAllowedWithExhaustedQuota")] + internal required bool OverageAllowedWithExhaustedQuota { get; set; } - /// Working directory where the shell command was executed. + /// Pay-as-you-go additional-usage budget cap in AI credits (1 credit = $0.01); present only when CAPI emits a finite value. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + [JsonInclude] + [JsonPropertyName("overageEntitlement")] + internal double? OverageEntitlement { get; set; } - /// Exit code from the completed shell command. - [JsonPropertyName("exitCode")] - public required long ExitCode { get; set; } + /// Percentage of quota remaining (0 to 100). + [JsonInclude] + [JsonPropertyName("remainingPercentage")] + internal required double RemainingPercentage { get; set; } - /// Path reported in the shell session's filesystem namespace when shell output exceeded the configured large-output threshold. + /// Date when the quota resets. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputFilePath")] - public string? OutputFilePath { get; set; } + [JsonInclude] + [JsonPropertyName("resetDate")] + internal DateTimeOffset? ResetDate { get; set; } - /// Output associated with this shell command, if available. May be partial, truncated, or a preview; not guaranteed to be full output. + /// Whether this snapshot uses token-based billing (AI-credits allocation). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputPreview")] - public string? OutputPreview { get; set; } + [JsonInclude] + [JsonPropertyName("tokenBasedBilling")] + internal bool? TokenBasedBilling { get; set; } - /// Whether outputPreview is known to be incomplete or truncated. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputTruncated")] - public bool? OutputTruncated { get; set; } + /// Whether usage is still permitted after quota exhaustion. + [JsonInclude] + [JsonPropertyName("usageAllowedWithExhaustedQuota")] + internal required bool UsageAllowedWithExhaustedQuota { get; set; } - /// Shell id, as assigned by Copilot runtime. - [JsonPropertyName("shellId")] - public required string ShellId { get; set; } + /// Number of requests already consumed. + [JsonInclude] + [JsonPropertyName("usedRequests")] + internal required long UsedRequests { get; set; } } -/// Image content block with base64-encoded data. -/// The image variant of . -public sealed partial class ToolExecutionCompleteContentImage : ToolExecutionCompleteContent +/// Content-free structural summary of the failing request for diagnosing malformed 4xx calls. +/// Nested data type for ModelCallFailureRequestFingerprint. +public sealed partial class ModelCallFailureRequestFingerprint { - /// - [JsonIgnore] - public override string Type => "image"; + /// Summed byte length of opaque or encrypted reasoning payloads. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("encryptedContentBytes")] + public long? EncryptedContentBytes { get; set; } - /// Base64-encoded image data. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Summed byte length of inline image payloads (data URLs and base64 sources). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("imageBytes")] + public long? ImageBytes { get; set; } - /// MIME type of the image (e.g., image/png, image/jpeg). - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } -} + /// Total number of image content parts. + [JsonPropertyName("imagePartCount")] + public required long ImagePartCount { get; set; } -/// Audio content block with base64-encoded data. -/// The audio variant of . -public sealed partial class ToolExecutionCompleteContentAudio : ToolExecutionCompleteContent -{ - /// - [JsonIgnore] - public override string Type => "audio"; + /// Image parts whose media type cannot be determined (rejected by strict providers). + [JsonPropertyName("imagePartsMissingMediaType")] + public required long ImagePartsMissingMediaType { get; set; } - /// Base64-encoded audio data. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Role of the final message in the request. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("lastMessageRole")] + public string? LastMessageRole { get; set; } - /// MIME type of the audio (e.g., audio/wav, audio/mpeg). - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } -} + /// Total number of messages in the request. + [JsonPropertyName("messageCount")] + public required long MessageCount { get; set; } -/// Icon image for a resource. -/// Nested data type for ToolExecutionCompleteContentResourceLinkIcon. -public sealed partial class ToolExecutionCompleteContentResourceLinkIcon -{ - /// MIME type of the icon image. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Tool calls whose name is missing or empty (rejected by strict providers). + [JsonPropertyName("namelessToolCallCount")] + public required long NamelessToolCallCount { get; set; } - /// Available icon sizes (e.g., ['16x16', '32x32']). + /// Number of messages carrying opaque or encrypted reasoning. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("sizes")] - public string[]? Sizes { get; set; } + [JsonPropertyName("reasoningItemCount")] + public long? ReasoningItemCount { get; set; } - /// URL or path to the icon image. - [JsonPropertyName("src")] - public required string Src { get; set; } + /// Total number of tool calls across assistant messages. + [JsonPropertyName("toolCallCount")] + public required long ToolCallCount { get; set; } - /// Theme variant this icon is intended for. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("theme")] - public ToolExecutionCompleteContentResourceLinkIconTheme? Theme { get; set; } + /// Number of "tool" result messages in the request. + [JsonPropertyName("toolResultMessageCount")] + public required long ToolResultMessageCount { get; set; } } -/// Resource link content block referencing an external resource. -/// The resource_link variant of . -public sealed partial class ToolExecutionCompleteContentResourceLink : ToolExecutionCompleteContent +/// Shell-aware path hints for a shell tool's command, captured at start time so consumers can snapshot a file's pre-image before the tool runs. +/// Nested data type for ToolExecutionStartShellToolInfo. +public sealed partial class ToolExecutionStartShellToolInfo { - /// - [JsonIgnore] - public override string Type => "resource_link"; - - /// Human-readable description of the resource. + /// The command with a redundant leading `cd` into the working directory removed, present only when there was one to remove. Computed with the same routine the shell driver applies before spawning, so a surface that renders this shows the text that actually runs. Consumers that display it should keep the original tool arguments available on demand. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("displayCommand")] + public string? DisplayCommand { get; set; } - /// Icons associated with this resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("icons")] - public ToolExecutionCompleteContentResourceLinkIcon[]? Icons { get; set; } + /// Whether the command includes a file write redirection (e.g., > or >>). + [JsonPropertyName("hasWriteFileRedirection")] + public required bool HasWriteFileRedirection { get; set; } - /// MIME type of the resource content. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// File paths the command may read or write, derived from the command at start time. Produced by the same shell-aware extractor as PermissionRequestShell.possiblePaths, so it is present even when the command is auto-approved and no permission request fires. + [JsonPropertyName("possiblePaths")] + public required string[] PossiblePaths { get; set; } +} - /// Resource name identifier. +/// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`. +/// Nested data type for ToolExecutionStartToolDescriptionMetaUI. +public sealed partial class ToolExecutionStartToolDescriptionMetaUI +{ + /// URI of the UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resourceUri")] + public string? ResourceUri { get; set; } + + /// Who can access this tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("visibility")] + public ToolExecutionStartToolDescriptionMetaUIVisibility[]? Visibility { get; set; } +} + +/// MCP Apps metadata for UI resource association. +/// Nested data type for ToolExecutionStartToolDescriptionMeta. +public sealed partial class ToolExecutionStartToolDescriptionMeta +{ + /// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ui")] + public ToolExecutionStartToolDescriptionMetaUI? Ui { get; set; } +} + +/// Tool definition metadata, present for MCP tools with MCP Apps support. +/// Nested data type for ToolExecutionStartToolDescription. +public sealed partial class ToolExecutionStartToolDescription +{ + /// MCP Apps metadata for UI resource association. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("_meta")] + public ToolExecutionStartToolDescriptionMeta? Meta { get; set; } + + /// Tool description. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Tool name. [JsonPropertyName("name")] public required string Name { get; set; } +} - /// Size of the resource in bytes. +/// Error details when the tool execution failed. +/// Nested data type for ToolExecutionCompleteError. +public sealed partial class ToolExecutionCompleteError +{ + /// Machine-readable error code. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("size")] - public long? Size { get; set; } + [JsonPropertyName("code")] + public string? Code { get; set; } - /// Human-readable display title for the resource. + /// Human-readable error message. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// What the user must do to recover, when the runtime knows of an action. Set on sandbox policy denials, where `message` names the rule that blocked the call but never the client affordance that relaxes it. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } + [JsonPropertyName("remediation")] + public RemediationAction? Remediation { get; set; } +} - /// URI identifying the resource. - [JsonPropertyName("uri")] - public required string Uri { get; set; } +/// A file mutation that was actually committed by a built-in file editing tool. +/// Nested data type for ToolExecutionCompleteFileEdit. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class ToolExecutionCompleteFileEdit +{ + /// Kind of mutation committed at this path. + [JsonPropertyName("kind")] + public required ToolExecutionCompleteFileEditKind Kind { get; set; } + + /// Absolute path in the session filesystem namespace. + [JsonPropertyName("path")] + public required string Path { get; set; } } -/// Embedded text resource contents identified by a URI, with an optional MIME type and a text payload. -/// Nested data type for EmbeddedTextResourceContents. -public sealed partial class EmbeddedTextResourceContents +/// Binary result returned by a tool for the model. +/// Nested data type for PersistedBinaryImage. +public sealed partial class PersistedBinaryImage { - /// MIME type of the text content. + /// Base64-encoded binary data. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// Human-readable description of the binary data. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Optional metadata from the producing tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } + + /// MIME type of the binary data. [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + public required string MimeType { get; set; } - /// Text content of the resource. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. + [JsonPropertyName("type")] + public required PersistedBinaryImageType Type { get; set; } +} - /// URI identifying the resource. - [JsonPropertyName("uri")] - public required string Uri { get; set; } +/// A binary result whose data was omitted from persistence due to the inline size limit. +/// Nested data type for OmittedBinaryResult. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class OmittedBinaryResult +{ + /// Decoded byte length of the omitted binary data. + [JsonPropertyName("byteLength")] + public required long ByteLength { get; set; } + + /// Human-readable description of the binary data. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Optional metadata from the producing tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } + + /// MIME type of the omitted binary data. + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } + + /// Why the binary data is absent: it exceeded the inline size limit, or its asset was unavailable. + [JsonPropertyName("omittedReason")] + public required OmittedBinaryOmittedReason OmittedReason { get; set; } + + /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. + [JsonPropertyName("type")] + public required OmittedBinaryType Type { get; set; } } -/// Embedded binary resource contents identified by a URI, with an optional MIME type and a base64-encoded blob. -/// Nested data type for EmbeddedBlobResourceContents. -public sealed partial class EmbeddedBlobResourceContents +/// A reference to binary data persisted once on a session.binary_asset event and shared by id. +/// Nested data type for BinaryAssetReference. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class BinaryAssetReference { - /// Base64-encoded binary content of the resource. - [Base64String] - [JsonPropertyName("blob")] - public required string Blob { get; set; } + /// Content-addressed id of the session.binary_asset event that holds this binary's bytes (e.g. "sha256:..."). + [JsonPropertyName("assetId")] + public required string AssetId { get; set; } - /// MIME type of the blob content. + /// Decoded byte length of the referenced binary data. + [JsonPropertyName("byteLength")] + public required long ByteLength { get; set; } + + /// Human-readable description of the binary data. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Optional metadata from the producing tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } + + /// MIME type of the referenced binary data. [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + public required string MimeType { get; set; } - /// URI identifying the resource. - [JsonPropertyName("uri")] - public required string Uri { get; set; } + /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. + [JsonPropertyName("type")] + public required BinaryAssetReferenceType Type { get; set; } } -/// The embedded resource contents, either text or base64-encoded binary. -/// JSON union data type for ToolExecutionCompleteContentResourceDetails. +/// A model-facing binary result as persisted: full inline data, a size-omitted marker, or a deduplicated asset reference. +/// JSON union data type for PersistedBinaryResult. [JsonConverter(typeof(Converter))] -public sealed partial class ToolExecutionCompleteContentResourceDetails +public sealed partial class PersistedBinaryResult { - /// Gets the value when this instance contains . - public EmbeddedTextResourceContents? EmbeddedTextResourceContents { get; } + /// Gets the value when this instance contains . + public PersistedBinaryImage? PersistedBinaryImage { get; } - /// Gets the value when this instance contains . - public EmbeddedBlobResourceContents? EmbeddedBlobResourceContents { get; } + /// Gets the value when this instance contains . + public OmittedBinaryResult? OmittedBinaryResult { get; } - /// Initializes a new instance of the class from . - public ToolExecutionCompleteContentResourceDetails(EmbeddedTextResourceContents value) + /// Gets the value when this instance contains . + public BinaryAssetReference? BinaryAssetReference { get; } + + /// Initializes a new instance of the class from . + public PersistedBinaryResult(PersistedBinaryImage value) { ArgumentNullException.ThrowIfNull(value); - EmbeddedTextResourceContents = value; + PersistedBinaryImage = value; } - /// Converts to . - public static implicit operator ToolExecutionCompleteContentResourceDetails(EmbeddedTextResourceContents value) => new(value); + /// Converts to . + public static implicit operator PersistedBinaryResult(PersistedBinaryImage value) => new(value); - /// Initializes a new instance of the class from . - public ToolExecutionCompleteContentResourceDetails(EmbeddedBlobResourceContents value) + /// Initializes a new instance of the class from . + public PersistedBinaryResult(OmittedBinaryResult value) { ArgumentNullException.ThrowIfNull(value); - EmbeddedBlobResourceContents = value; + OmittedBinaryResult = value; } - /// Converts to . - public static implicit operator ToolExecutionCompleteContentResourceDetails(EmbeddedBlobResourceContents value) => new(value); + /// Converts to . + public static implicit operator PersistedBinaryResult(OmittedBinaryResult value) => new(value); - /// Provides a for serializing instances. + /// Initializes a new instance of the class from . + public PersistedBinaryResult(BinaryAssetReference value) + { + ArgumentNullException.ThrowIfNull(value); + BinaryAssetReference = value; + } + + /// Converts to . + public static implicit operator PersistedBinaryResult(BinaryAssetReference value) => new(value); + + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override ToolExecutionCompleteContentResourceDetails Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PersistedBinaryResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) { - throw new JsonException("Expected JSON object for ToolExecutionCompleteContentResourceDetails."); + throw new JsonException("Expected JSON object for PersistedBinaryResult."); } using var document = JsonDocument.ParseValue(ref reader); var element = document.RootElement; - if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("text", out _) && !element.TryGetProperty("blob", out _)) + if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("data", out _) && !element.TryGetProperty("assetId", out _) && !element.TryGetProperty("byteLength", out _) && !element.TryGetProperty("omittedReason", out _)) { - var embeddedTextResourceContents = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.EmbeddedTextResourceContents); - return embeddedTextResourceContents is null ? throw new JsonException("Expected EmbeddedTextResourceContents value.") : new ToolExecutionCompleteContentResourceDetails(embeddedTextResourceContents); + var persistedBinaryImage = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.PersistedBinaryImage); + return persistedBinaryImage is null ? throw new JsonException("Expected PersistedBinaryImage value.") : new PersistedBinaryResult(persistedBinaryImage); } - if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("blob", out _) && !element.TryGetProperty("text", out _)) + if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("omittedReason", out _) && !element.TryGetProperty("assetId", out _) && !element.TryGetProperty("data", out _)) { - var embeddedBlobResourceContents = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.EmbeddedBlobResourceContents); - return embeddedBlobResourceContents is null ? throw new JsonException("Expected EmbeddedBlobResourceContents value.") : new ToolExecutionCompleteContentResourceDetails(embeddedBlobResourceContents); + var omittedBinaryResult = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.OmittedBinaryResult); + return omittedBinaryResult is null ? throw new JsonException("Expected OmittedBinaryResult value.") : new PersistedBinaryResult(omittedBinaryResult); } - - throw new JsonException("JSON value did not match any ToolExecutionCompleteContentResourceDetails variant."); - } - + if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("assetId", out _) && !element.TryGetProperty("data", out _) && !element.TryGetProperty("omittedReason", out _)) + { + var binaryAssetReference = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.BinaryAssetReference); + return binaryAssetReference is null ? throw new JsonException("Expected BinaryAssetReference value.") : new PersistedBinaryResult(binaryAssetReference); + } + + throw new JsonException("JSON value did not match any PersistedBinaryResult variant."); + } + /// - public override void Write(Utf8JsonWriter writer, ToolExecutionCompleteContentResourceDetails value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PersistedBinaryResult value, JsonSerializerOptions options) { - if (value.EmbeddedTextResourceContents is { } embeddedTextResourceContents) + if (value.PersistedBinaryImage is { } persistedBinaryImage) { - JsonSerializer.Serialize(writer, embeddedTextResourceContents, SessionEventsJsonContext.Default.EmbeddedTextResourceContents); + JsonSerializer.Serialize(writer, persistedBinaryImage, SessionEventsJsonContext.Default.PersistedBinaryImage); return; } - if (value.EmbeddedBlobResourceContents is { } embeddedBlobResourceContents) + if (value.OmittedBinaryResult is { } omittedBinaryResult) { - JsonSerializer.Serialize(writer, embeddedBlobResourceContents, SessionEventsJsonContext.Default.EmbeddedBlobResourceContents); + JsonSerializer.Serialize(writer, omittedBinaryResult, SessionEventsJsonContext.Default.OmittedBinaryResult); + return; + } + if (value.BinaryAssetReference is { } binaryAssetReference) + { + JsonSerializer.Serialize(writer, binaryAssetReference, SessionEventsJsonContext.Default.BinaryAssetReference); return; } - throw new JsonException("No ToolExecutionCompleteContentResourceDetails variant value is set."); + throw new JsonException("No PersistedBinaryResult variant value is set."); } } } -/// Embedded resource content block with inline text or binary data. -/// The resource variant of . -public sealed partial class ToolExecutionCompleteContentResource : ToolExecutionCompleteContent +/// A source supplied by a tool that should be made available to the model as citable content. +/// Nested data type for CitableSource. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class CitableSource +{ + /// The source text made available to the model as citable content. + [JsonPropertyName("content")] + public required string Content { get; set; } + + /// Stable identifier for this source within the tool result. Used for deduplication and may be used by future provider integrations to correlate response citations back to the originating source. + [JsonPropertyName("id")] + public required string Id { get; set; } + + /// File path relative to the agent's workspace root, when the source is a file. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("path")] + public string? Path { get; set; } + + /// Human-readable title of the source. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// URL of the source, when it is a web resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("url")] + public string? Url { get; set; } +} + +/// Plain text content block. +/// The text variant of . +public sealed partial class ToolExecutionCompleteContentText : ToolExecutionCompleteContent { /// [JsonIgnore] - public override string Type => "resource"; + public override string Type => "text"; - /// The embedded resource contents, either text or base64-encoded binary. - [JsonPropertyName("resource")] - public required ToolExecutionCompleteContentResourceDetails Resource { get; set; } + /// The text content. + [JsonPropertyName("text")] + public required string Text { get; set; } } -/// A content block within a tool result, which may be text, terminal output, image, audio, or a resource. -/// Polymorphic base type discriminated by type. -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ToolExecutionCompleteContentText), "text")] -[JsonDerivedType(typeof(ToolExecutionCompleteContentTerminal), "terminal")] -[JsonDerivedType(typeof(ToolExecutionCompleteContentShellExit), "shell_exit")] -[JsonDerivedType(typeof(ToolExecutionCompleteContentImage), "image")] -[JsonDerivedType(typeof(ToolExecutionCompleteContentAudio), "audio")] -[JsonDerivedType(typeof(ToolExecutionCompleteContentResourceLink), "resource_link")] -[JsonDerivedType(typeof(ToolExecutionCompleteContentResource), "resource")] -public partial class ToolExecutionCompleteContent +/// Deprecated for shell command exit metadata. Use ToolExecutionCompleteContentShellExit instead. +/// The terminal variant of . +[EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER +[Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else +[Obsolete("This member is deprecated and will be removed in a future version.")] +#endif +public sealed partial class ToolExecutionCompleteContentTerminal : ToolExecutionCompleteContent { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Type => "terminal"; + /// Working directory where the command was executed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } -/// CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains. -/// Nested data type for ToolExecutionCompleteUIResourceMetaUICsp. -public sealed partial class ToolExecutionCompleteUIResourceMetaUICsp + /// Process exit code, if the command has completed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } + + /// Terminal/shell output text. + [JsonPropertyName("text")] + public required string Text { get; set; } +} + +/// Shell command exit metadata with optional output preview. +/// The shell_exit variant of . +public sealed partial class ToolExecutionCompleteContentShellExit : ToolExecutionCompleteContent { - /// Domains the UI resource may use as document base URIs. + /// + [JsonIgnore] + public override string Type => "shell_exit"; + + /// Working directory where the shell command was executed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("baseUriDomains")] - public string[]? BaseUriDomains { get; set; } + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Domains the UI resource may connect to. + /// Exit code from the completed shell command. + [JsonPropertyName("exitCode")] + public required long ExitCode { get; set; } + + /// Path reported in the shell session's filesystem namespace when shell output exceeded the configured large-output threshold. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("connectDomains")] - public string[]? ConnectDomains { get; set; } + [JsonPropertyName("outputFilePath")] + public string? OutputFilePath { get; set; } - /// Domains the UI resource may embed as nested frames. + /// Output associated with this shell command, if available. May be partial, truncated, or a preview; not guaranteed to be full output. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("frameDomains")] - public string[]? FrameDomains { get; set; } + [JsonPropertyName("outputPreview")] + public string? OutputPreview { get; set; } - /// Domains from which the UI resource may load scripts, styles, images, and other resources. + /// Whether outputPreview is known to be incomplete or truncated. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resourceDomains")] - public string[]? ResourceDomains { get; set; } -} + [JsonPropertyName("outputTruncated")] + public bool? OutputTruncated { get; set; } -/// Marker object for camera permission on an MCP Apps UI resource. -/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsCamera. -public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsCamera -{ + /// Shell id, as assigned by Copilot runtime. + [JsonPropertyName("shellId")] + public required string ShellId { get; set; } } -/// Marker object for clipboard-write permission on an MCP Apps UI resource. -/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite. -public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite +/// Image content block with base64-encoded data. +/// The image variant of . +public sealed partial class ToolExecutionCompleteContentImage : ToolExecutionCompleteContent { -} + /// + [JsonIgnore] + public override string Type => "image"; -/// Marker object for geolocation permission on an MCP Apps UI resource. -/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation. -public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation -{ + /// Base64-encoded image data. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// MIME type of the image (e.g., image/png, image/jpeg). + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } } -/// Marker object for microphone permission on an MCP Apps UI resource. -/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone. -public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone +/// Audio content block with base64-encoded data. +/// The audio variant of . +public sealed partial class ToolExecutionCompleteContentAudio : ToolExecutionCompleteContent { + /// + [JsonIgnore] + public override string Type => "audio"; + + /// Base64-encoded audio data. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// MIME type of the audio (e.g., audio/wav, audio/mpeg). + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } } -/// Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write. -/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissions. -public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissions +/// Icon image for a resource. +/// Nested data type for ToolExecutionCompleteContentResourceLinkIcon. +public sealed partial class ToolExecutionCompleteContentResourceLinkIcon { - /// Marker object for camera permission on an MCP Apps UI resource. + /// MIME type of the icon image. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("camera")] - public ToolExecutionCompleteUIResourceMetaUIPermissionsCamera? Camera { get; set; } + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } - /// Marker object for clipboard-write permission on an MCP Apps UI resource. + /// Available icon sizes (e.g., ['16x16', '32x32']). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("clipboardWrite")] - public ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite? ClipboardWrite { get; set; } + [JsonPropertyName("sizes")] + public string[]? Sizes { get; set; } - /// Marker object for geolocation permission on an MCP Apps UI resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("geolocation")] - public ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation? Geolocation { get; set; } + /// URL or path to the icon image. + [JsonPropertyName("src")] + public required string Src { get; set; } - /// Marker object for microphone permission on an MCP Apps UI resource. + /// Theme variant this icon is intended for. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("microphone")] - public ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone? Microphone { get; set; } + [JsonPropertyName("theme")] + public ToolExecutionCompleteContentResourceLinkIconTheme? Theme { get; set; } } -/// MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference. -/// Nested data type for ToolExecutionCompleteUIResourceMetaUI. -public sealed partial class ToolExecutionCompleteUIResourceMetaUI +/// Resource link content block referencing an external resource. +/// The resource_link variant of . +public sealed partial class ToolExecutionCompleteContentResourceLink : ToolExecutionCompleteContent { - /// CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("csp")] - public ToolExecutionCompleteUIResourceMetaUICsp? Csp { get; set; } + /// + [JsonIgnore] + public override string Type => "resource_link"; - /// Optional dedicated origin for the rendered MCP Apps UI resource. + /// Human-readable description of the resource. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("domain")] - public string? Domain { get; set; } + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write. + /// Icons associated with this resource. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("permissions")] - public ToolExecutionCompleteUIResourceMetaUIPermissions? Permissions { get; set; } + [JsonPropertyName("icons")] + public ToolExecutionCompleteContentResourceLinkIcon[]? Icons { get; set; } - /// Whether the host should render a border around the MCP Apps UI resource. + /// MIME type of the resource content. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("prefersBorder")] - public bool? PrefersBorder { get; set; } -} + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } -/// Resource-level UI metadata (CSP, permissions, visual preferences). -/// Nested data type for ToolExecutionCompleteUIResourceMeta. -public sealed partial class ToolExecutionCompleteUIResourceMeta -{ - /// MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ui")] - public ToolExecutionCompleteUIResourceMetaUI? Ui { get; set; } -} + /// Resource name identifier. + [JsonPropertyName("name")] + public required string Name { get; set; } -/// MCP Apps UI resource content for rendering in a sandboxed iframe. -/// Nested data type for ToolExecutionCompleteUIResource. -public sealed partial class ToolExecutionCompleteUIResource -{ - /// Resource-level UI metadata (CSP, permissions, visual preferences). + /// Size of the resource in bytes. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("_meta")] - public ToolExecutionCompleteUIResourceMeta? Meta { get; set; } + [JsonPropertyName("size")] + public long? Size { get; set; } - /// Base64-encoded HTML content. + /// Human-readable display title for the resource. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("blob")] - public string? Blob { get; set; } + [JsonPropertyName("title")] + public string? Title { get; set; } - /// MIME type of the content. - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// URI identifying the resource. + [JsonPropertyName("uri")] + public required string Uri { get; set; } +} - /// HTML content as a string. +/// Embedded text resource contents identified by a URI, with an optional MIME type and a text payload. +/// Nested data type for EmbeddedTextResourceContents. +public sealed partial class EmbeddedTextResourceContents +{ + /// MIME type of the text content. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Text content of the resource. [JsonPropertyName("text")] - public string? Text { get; set; } + public required string Text { get; set; } - /// The ui:// URI of the resource. + /// URI identifying the resource. [JsonPropertyName("uri")] public required string Uri { get; set; } } -/// Tool execution result on success. -/// Nested data type for ToolExecutionCompleteResult. -public sealed partial class ToolExecutionCompleteResult +/// Embedded binary resource contents identified by a URI, with an optional MIME type and a base64-encoded blob. +/// Nested data type for EmbeddedBlobResourceContents. +public sealed partial class EmbeddedBlobResourceContents { - /// Model-facing binary results (base64 inline or size-omitted markers) sent to the LLM for this tool call. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("binaryResultsForLlm")] - public PersistedBinaryResult[]? BinaryResultsForLlm { get; set; } + /// Base64-encoded binary content of the resource. + [Base64String] + [JsonPropertyName("blob")] + public required string Blob { get; set; } - /// Provider-neutral source material this tool makes available to the model as citable content. Persisted so it survives session resume. Experimental. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + /// MIME type of the blob content. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("citableSources")] - public CitableSource[]? CitableSources { get; set; } + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } - /// Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency. - [JsonPropertyName("content")] - public required string Content { get; set; } + /// URI identifying the resource. + [JsonPropertyName("uri")] + public required string Uri { get; set; } +} - /// Structured content blocks (text, images, audio, resources) returned by the tool in their native format. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("contents")] - public ToolExecutionCompleteContent[]? Contents { get; set; } +/// The embedded resource contents, either text or base64-encoded binary. +/// JSON union data type for ToolExecutionCompleteContentResourceDetails. +[JsonConverter(typeof(Converter))] +public sealed partial class ToolExecutionCompleteContentResourceDetails +{ + /// Gets the value when this instance contains . + public EmbeddedTextResourceContents? EmbeddedTextResourceContents { get; } - /// Detailed tool result for UI/timeline display, preserving complete content such as diffs for most tools. Successful skill invocations intentionally use the concise model-facing content here; the authoritative skill body is carried by the corresponding skill invocation event. Falls back to content when absent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("detailedContent")] - public string? DetailedContent { get; set; } + /// Gets the value when this instance contains . + public EmbeddedBlobResourceContents? EmbeddedBlobResourceContents { get; } - /// FIDES IFC label projected from tool ingress metadata (MCP `CallToolResult._meta` or synthesized built-in ingress labels) — persisted as `{ ifc: ... }` (only the `ifc` key, not the whole `_meta`). Persisted so the FIDES IFC label survives session resume: the engine rehydrates accumulated taint by replaying these on load. Populated for ingress sources when FIDES IFC is on. Experimental. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mcpMeta")] - public JsonElement? McpMeta { get; set; } + /// Initializes a new instance of the class from . + public ToolExecutionCompleteContentResourceDetails(EmbeddedTextResourceContents value) + { + ArgumentNullException.ThrowIfNull(value); + EmbeddedTextResourceContents = value; + } - /// Structured content (arbitrary JSON) returned verbatim by the MCP tool. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("structuredContent")] - public JsonElement? StructuredContent { get; set; } + /// Converts to . + public static implicit operator ToolExecutionCompleteContentResourceDetails(EmbeddedTextResourceContents value) => new(value); - /// MCP Apps UI resource content for rendering in a sandboxed iframe. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("uiResource")] - public ToolExecutionCompleteUIResource? UiResource { get; set; } -} + /// Initializes a new instance of the class from . + public ToolExecutionCompleteContentResourceDetails(EmbeddedBlobResourceContents value) + { + ArgumentNullException.ThrowIfNull(value); + EmbeddedBlobResourceContents = value; + } -/// Experimental shell completion facts retained independently of the full tool result. -/// Nested data type for ToolExecutionCompleteShellExecution. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed partial class ToolExecutionCompleteShellExecution -{ - /// Process exit code reported by the shell driver. - [JsonPropertyName("exitCode")] - public required long ExitCode { get; set; } + /// Converts to . + public static implicit operator ToolExecutionCompleteContentResourceDetails(EmbeddedBlobResourceContents value) => new(value); + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ToolExecutionCompleteContentResourceDetails Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + throw new JsonException("Expected JSON object for ToolExecutionCompleteContentResourceDetails."); + } + + using var document = JsonDocument.ParseValue(ref reader); + var element = document.RootElement; + if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("text", out _) && !element.TryGetProperty("blob", out _)) + { + var embeddedTextResourceContents = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.EmbeddedTextResourceContents); + return embeddedTextResourceContents is null ? throw new JsonException("Expected EmbeddedTextResourceContents value.") : new ToolExecutionCompleteContentResourceDetails(embeddedTextResourceContents); + } + if (element.ValueKind == JsonValueKind.Object && element.TryGetProperty("blob", out _) && !element.TryGetProperty("text", out _)) + { + var embeddedBlobResourceContents = JsonSerializer.Deserialize(element, SessionEventsJsonContext.Default.EmbeddedBlobResourceContents); + return embeddedBlobResourceContents is null ? throw new JsonException("Expected EmbeddedBlobResourceContents value.") : new ToolExecutionCompleteContentResourceDetails(embeddedBlobResourceContents); + } + + throw new JsonException("JSON value did not match any ToolExecutionCompleteContentResourceDetails variant."); + } + + /// + public override void Write(Utf8JsonWriter writer, ToolExecutionCompleteContentResourceDetails value, JsonSerializerOptions options) + { + if (value.EmbeddedTextResourceContents is { } embeddedTextResourceContents) + { + JsonSerializer.Serialize(writer, embeddedTextResourceContents, SessionEventsJsonContext.Default.EmbeddedTextResourceContents); + return; + } + if (value.EmbeddedBlobResourceContents is { } embeddedBlobResourceContents) + { + JsonSerializer.Serialize(writer, embeddedBlobResourceContents, SessionEventsJsonContext.Default.EmbeddedBlobResourceContents); + return; + } + + throw new JsonException("No ToolExecutionCompleteContentResourceDetails variant value is set."); + } + } } -/// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`. -/// Nested data type for ToolExecutionCompleteToolDescriptionMetaUI. -public sealed partial class ToolExecutionCompleteToolDescriptionMetaUI +/// Embedded resource content block with inline text or binary data. +/// The resource variant of . +public sealed partial class ToolExecutionCompleteContentResource : ToolExecutionCompleteContent { - /// URI of the UI resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resourceUri")] - public string? ResourceUri { get; set; } + /// + [JsonIgnore] + public override string Type => "resource"; - /// Who can access this tool. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("visibility")] - public ToolExecutionCompleteToolDescriptionMetaUIVisibility[]? Visibility { get; set; } + /// The embedded resource contents, either text or base64-encoded binary. + [JsonPropertyName("resource")] + public required ToolExecutionCompleteContentResourceDetails Resource { get; set; } } -/// MCP Apps metadata for UI resource association. -/// Nested data type for ToolExecutionCompleteToolDescriptionMeta. -public sealed partial class ToolExecutionCompleteToolDescriptionMeta +/// A content block within a tool result, which may be text, terminal output, image, audio, or a resource. +/// Polymorphic base type discriminated by type. +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(ToolExecutionCompleteContentText), "text")] +[JsonDerivedType(typeof(ToolExecutionCompleteContentTerminal), "terminal")] +[JsonDerivedType(typeof(ToolExecutionCompleteContentShellExit), "shell_exit")] +[JsonDerivedType(typeof(ToolExecutionCompleteContentImage), "image")] +[JsonDerivedType(typeof(ToolExecutionCompleteContentAudio), "audio")] +[JsonDerivedType(typeof(ToolExecutionCompleteContentResourceLink), "resource_link")] +[JsonDerivedType(typeof(ToolExecutionCompleteContentResource), "resource")] +public partial class ToolExecutionCompleteContent { - /// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ui")] - public ToolExecutionCompleteToolDescriptionMetaUI? Ui { get; set; } + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Tool definition metadata, present for MCP tools with MCP Apps support. -/// Nested data type for ToolExecutionCompleteToolDescription. -public sealed partial class ToolExecutionCompleteToolDescription + +/// CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains. +/// Nested data type for ToolExecutionCompleteUIResourceMetaUICsp. +public sealed partial class ToolExecutionCompleteUIResourceMetaUICsp { - /// MCP Apps metadata for UI resource association. + /// Domains the UI resource may use as document base URIs. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("_meta")] - public ToolExecutionCompleteToolDescriptionMeta? Meta { get; set; } + [JsonPropertyName("baseUriDomains")] + public string[]? BaseUriDomains { get; set; } - /// Tool description. + /// Domains the UI resource may connect to. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("connectDomains")] + public string[]? ConnectDomains { get; set; } - /// Tool name. - [JsonPropertyName("name")] - public required string Name { get; set; } -} + /// Domains the UI resource may embed as nested frames. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("frameDomains")] + public string[]? FrameDomains { get; set; } -/// Effective sandbox filesystem rules, in policy order. Only populated when content capture is enabled, since these are real host paths. -/// Nested data type for SandboxFilesystemPolicyDetails. + /// Domains from which the UI resource may load scripts, styles, images, and other resources. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resourceDomains")] + public string[]? ResourceDomains { get; set; } +} + +/// Marker object for camera permission on an MCP Apps UI resource. +/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsCamera. +public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsCamera +{ +} + +/// Marker object for clipboard-write permission on an MCP Apps UI resource. +/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite. +public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite +{ +} + +/// Marker object for geolocation permission on an MCP Apps UI resource. +/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation. +public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation +{ +} + +/// Marker object for microphone permission on an MCP Apps UI resource. +/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone. +public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone +{ +} + +/// Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write. +/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissions. +public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissions +{ + /// Marker object for camera permission on an MCP Apps UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("camera")] + public ToolExecutionCompleteUIResourceMetaUIPermissionsCamera? Camera { get; set; } + + /// Marker object for clipboard-write permission on an MCP Apps UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("clipboardWrite")] + public ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite? ClipboardWrite { get; set; } + + /// Marker object for geolocation permission on an MCP Apps UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("geolocation")] + public ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation? Geolocation { get; set; } + + /// Marker object for microphone permission on an MCP Apps UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("microphone")] + public ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone? Microphone { get; set; } +} + +/// MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference. +/// Nested data type for ToolExecutionCompleteUIResourceMetaUI. +public sealed partial class ToolExecutionCompleteUIResourceMetaUI +{ + /// CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("csp")] + public ToolExecutionCompleteUIResourceMetaUICsp? Csp { get; set; } + + /// Optional dedicated origin for the rendered MCP Apps UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("domain")] + public string? Domain { get; set; } + + /// Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("permissions")] + public ToolExecutionCompleteUIResourceMetaUIPermissions? Permissions { get; set; } + + /// Whether the host should render a border around the MCP Apps UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("prefersBorder")] + public bool? PrefersBorder { get; set; } +} + +/// Resource-level UI metadata (CSP, permissions, visual preferences). +/// Nested data type for ToolExecutionCompleteUIResourceMeta. +public sealed partial class ToolExecutionCompleteUIResourceMeta +{ + /// MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ui")] + public ToolExecutionCompleteUIResourceMetaUI? Ui { get; set; } +} + +/// MCP Apps UI resource content for rendering in a sandboxed iframe. +/// Nested data type for ToolExecutionCompleteUIResource. +public sealed partial class ToolExecutionCompleteUIResource +{ + /// Resource-level UI metadata (CSP, permissions, visual preferences). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("_meta")] + public ToolExecutionCompleteUIResourceMeta? Meta { get; set; } + + /// Base64-encoded HTML content. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("blob")] + public string? Blob { get; set; } + + /// MIME type of the content. + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } + + /// HTML content as a string. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("text")] + public string? Text { get; set; } + + /// The ui:// URI of the resource. + [JsonPropertyName("uri")] + public required string Uri { get; set; } +} + +/// Tool execution result on success. +/// Nested data type for ToolExecutionCompleteResult. +public sealed partial class ToolExecutionCompleteResult +{ + /// Model-facing binary results (base64 inline or size-omitted markers) sent to the LLM for this tool call. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("binaryResultsForLlm")] + public PersistedBinaryResult[]? BinaryResultsForLlm { get; set; } + + /// Provider-neutral source material this tool makes available to the model as citable content. Persisted so it survives session resume. Experimental. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("citableSources")] + public CitableSource[]? CitableSources { get; set; } + + /// Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency. + [JsonPropertyName("content")] + public required string Content { get; set; } + + /// Structured content blocks (text, images, audio, resources) returned by the tool in their native format. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("contents")] + public ToolExecutionCompleteContent[]? Contents { get; set; } + + /// Detailed tool result for UI/timeline display, preserving complete content such as diffs for most tools. Successful skill invocations intentionally use the concise model-facing content here; the authoritative skill body is carried by the corresponding skill invocation event. Falls back to content when absent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("detailedContent")] + public string? DetailedContent { get; set; } + + /// FIDES IFC label projected from tool ingress metadata (MCP `CallToolResult._meta` or synthesized built-in ingress labels) — persisted as `{ ifc: ... }` (only the `ifc` key, not the whole `_meta`). Persisted so the FIDES IFC label survives session resume: the engine rehydrates accumulated taint by replaying these on load. Populated for ingress sources when FIDES IFC is on. Experimental. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mcpMeta")] + public JsonElement? McpMeta { get; set; } + + /// Structured content (arbitrary JSON) returned verbatim by the MCP tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("structuredContent")] + public JsonElement? StructuredContent { get; set; } + + /// MCP Apps UI resource content for rendering in a sandboxed iframe. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("uiResource")] + public ToolExecutionCompleteUIResource? UiResource { get; set; } +} + +/// Experimental shell completion facts retained independently of the full tool result. +/// Nested data type for ToolExecutionCompleteShellExecution. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class ToolExecutionCompleteShellExecution +{ + /// Process exit code reported by the shell driver. + [JsonPropertyName("exitCode")] + public required long ExitCode { get; set; } +} + +/// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`. +/// Nested data type for ToolExecutionCompleteToolDescriptionMetaUI. +public sealed partial class ToolExecutionCompleteToolDescriptionMetaUI +{ + /// URI of the UI resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resourceUri")] + public string? ResourceUri { get; set; } + + /// Who can access this tool. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("visibility")] + public ToolExecutionCompleteToolDescriptionMetaUIVisibility[]? Visibility { get; set; } +} + +/// MCP Apps metadata for UI resource association. +/// Nested data type for ToolExecutionCompleteToolDescriptionMeta. +public sealed partial class ToolExecutionCompleteToolDescriptionMeta +{ + /// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ui")] + public ToolExecutionCompleteToolDescriptionMetaUI? Ui { get; set; } +} + +/// Tool definition metadata, present for MCP tools with MCP Apps support. +/// Nested data type for ToolExecutionCompleteToolDescription. +public sealed partial class ToolExecutionCompleteToolDescription +{ + /// MCP Apps metadata for UI resource association. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("_meta")] + public ToolExecutionCompleteToolDescriptionMeta? Meta { get; set; } + + /// Tool description. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Tool name. + [JsonPropertyName("name")] + public required string Name { get; set; } +} + +/// Effective sandbox filesystem rules, in policy order. Only populated when content capture is enabled, since these are real host paths. +/// Nested data type for SandboxFilesystemPolicyDetails. public sealed partial class SandboxFilesystemPolicyDetails { /// Paths the sandboxed process may not access at all. @@ -11208,6 +12032,34 @@ public override bool? ManagedApprovalRequired public string? Warning { get; set; } } +/// A named, complete UTF-8 text snapshot for a pending file operation. +/// Nested data type for PermissionWriteFileContent. +public sealed partial class PermissionWriteFileContent +{ + /// Complete file contents, including an empty string for an empty file. + [JsonPropertyName("content")] + public required string Content { get; set; } + + /// Absolute path in the session filesystem namespace. + [JsonPropertyName("path")] + public required string Path { get; set; } +} + +/// Complete text snapshots for one proposed file change. At least one side is present. Different before and after paths describe a move. +/// Nested data type for PermissionWriteFileEdit. +public sealed partial class PermissionWriteFileEdit +{ + /// Complete file content the operation plans to write. Absent only when the file is being deleted. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("after")] + public PermissionWriteFileContent? After { get; set; } + + /// File content read while planning the operation. Absent only when the file is being created. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("before")] + public PermissionWriteFileContent? Before { get; set; } +} + /// File write permission request. /// The write variant of . public sealed partial class PermissionRequestWrite : PermissionRequest @@ -11224,6 +12076,11 @@ public sealed partial class PermissionRequestWrite : PermissionRequest [JsonPropertyName("diff")] public required string Diff { get; set; } + /// Complete before/after text previews captured while planning this request. Omitted when a complete preview is unavailable, including pre-read sandbox requests and non-UTF-8 files. Missing sides mean creation or deletion, not unavailable content. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("fileEdits")] + public PermissionWriteFileEdit[]? FileEdits { get; set; } + /// Path of the file being written to. [JsonPropertyName("fileName")] public required string FileName { get; set; } @@ -11872,6 +12729,11 @@ public sealed partial class PermissionPromptRequestWrite : PermissionPromptReque [JsonPropertyName("diff")] public required string Diff { get; set; } + /// Complete before/after text previews captured while planning this request. Omitted when a complete preview is unavailable, including pre-read sandbox requests and non-UTF-8 files. Missing sides mean creation or deletion, not unavailable content. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("fileEdits")] + public PermissionWriteFileEdit[]? FileEdits { get; set; } + /// Path of the file being written to. [JsonPropertyName("fileName")] public required string FileName { get; set; } @@ -12849,6 +13711,20 @@ public sealed partial class SessionLimitsExhaustedResponse public double? MaxAiCredits { get; set; } } +/// Reusable managed permission evaluation context. Treat permissions as runtime-owned policy data and retain it verbatim; it includes source-aware composition metadata. This is a snapshot, not a capability or approval token; only use contexts obtained from trusted policy sources. +/// Nested data type for ManagedPermissionsContext. +public sealed partial class ManagedPermissionsContext +{ + /// Policy could not be determined; evaluation must deny every operation. + [JsonPropertyName("failClosed")] + public required bool FailClosed { get; set; } + + /// Runtime-owned composed permissions object. Absent when no permission policy is configured. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("permissions")] + public JsonElement? Permissions { get; set; } +} + /// A single slash command available in the session, as listed by the `commands.changed` event. /// Nested data type for CommandsChangedCommand. public sealed partial class CommandsChangedCommand @@ -13193,116 +14069,765 @@ public sealed partial class CanvasRegistryChangedCanvas [JsonPropertyName("actions")] public CanvasRegistryChangedCanvasAction[]? Actions { get; set; } - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public required string CanvasId { get; set; } + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public required string CanvasId { get; set; } + + /// Short, single-sentence description shown to the agent in canvas catalogs. + [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("description")] + public required string Description { get; set; } + + /// Human-readable canvas name. + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } + + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public required string ExtensionId { get; set; } + + /// Owning extension display name, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("extensionName")] + public string? ExtensionName { get; set; } + + /// Host-local PNG path for the canvas icon, when supplied. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("icon")] + public string? Icon { get; set; } + + /// JSON Schema for canvas open input. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("inputSchema")] + public JsonElement? InputSchema { get; set; } +} + +/// Set when the underlying tools/call threw an error before returning a CallToolResult. +/// Nested data type for McpAppToolCallCompleteError. +public sealed partial class McpAppToolCallCompleteError +{ + /// Human-readable error message. + [JsonPropertyName("message")] + public required string Message { get; set; } +} + +/// MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result. +/// Nested data type for McpAppToolCallCompleteToolMetaUI. +public sealed partial class McpAppToolCallCompleteToolMetaUI +{ + /// `ui://` URI declared by the tool's `_meta.ui.resourceUri`. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resourceUri")] + public string? ResourceUri { get; set; } + + /// Tool visibility per SEP-1865 (typically a subset of `["model","app"]`). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("visibility")] + public string[]? Visibility { get; set; } +} + +/// 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. +/// Nested data type for McpAppToolCallCompleteToolMeta. +public sealed partial class McpAppToolCallCompleteToolMeta +{ + /// MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ui")] + public McpAppToolCallCompleteToolMetaUI? Ui { get; set; } +} + +/// Extensible routing preference for the virtual `auto` model. New identifiers must be advertised and enabled by the provider. `fast` is an integrator-only latency preset. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct AutoTier : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public AutoTier(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Optimize for efficiency. + public static AutoTier Efficiency { get; } = new("efficiency"); + + /// Balance efficiency and intelligence. + public static AutoTier Balance { get; } = new("balance"); + + /// Optimize for intelligence. + public static AutoTier Intelligence { get; } = new("intelligence"); + + /// Integrator-only preset that optimizes for latency. + public static AutoTier Fast { get; } = new("fast"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(AutoTier left, AutoTier right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(AutoTier left, AutoTier right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is AutoTier other && Equals(other); + + /// + public bool Equals(AutoTier other) => string.Equals(Value, other.Value, StringComparison.Ordinal); + + /// + public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override AutoTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, AutoTier value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutoTier)); + } + } +} + +/// Hosting platform type of the repository (github or ado). +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct WorkingDirectoryContextHostType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public WorkingDirectoryContextHostType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Repository is hosted on GitHub. + public static WorkingDirectoryContextHostType GitHub { get; } = new("github"); + + /// Repository is hosted on Azure DevOps. + public static WorkingDirectoryContextHostType Ado { get; } = new("ado"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(WorkingDirectoryContextHostType left, WorkingDirectoryContextHostType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(WorkingDirectoryContextHostType left, WorkingDirectoryContextHostType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is WorkingDirectoryContextHostType other && Equals(other); + + /// + public bool Equals(WorkingDirectoryContextHostType 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 WorkingDirectoryContextHostType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, WorkingDirectoryContextHostType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(WorkingDirectoryContextHostType)); + } + } +} + +/// Allowed values for the `ContextTier` enumeration. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ContextTier : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ContextTier(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 ContextTier Default { get; } = new("default"); + + /// Extended context tier with a larger context window. + public static ContextTier LongContext { get; } = new("long_context"); + + /// 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 !=(ContextTier left, ContextTier right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ContextTier other && Equals(other); + + /// + public bool Equals(ContextTier 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 ContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ContextTier value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ContextTier)); + } + } +} + +/// Reasoning summary mode used for model calls, if applicable (e.g. "none", "concise", "detailed"). +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ReasoningSummary : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ReasoningSummary(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Do not request reasoning summaries from the model. + public static ReasoningSummary None { get; } = new("none"); + + /// Request a concise summary of the model's reasoning. + public static ReasoningSummary Concise { get; } = new("concise"); + + /// Request a detailed summary of the model's reasoning. + public static ReasoningSummary Detailed { get; } = new("detailed"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ReasoningSummary left, ReasoningSummary right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ReasoningSummary left, ReasoningSummary right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ReasoningSummary other && Equals(other); + + /// + public bool Equals(ReasoningSummary 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 ReasoningSummary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ReasoningSummary value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ReasoningSummary)); + } + } +} + +/// Output verbosity level used for supported model calls (e.g. "low", "medium", "high"). +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct Verbosity : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public Verbosity(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// A terse response was requested. + public static Verbosity Low { get; } = new("low"); + + /// A medium amount of response detail was requested. + public static Verbosity Medium { get; } = new("medium"); + + /// A more detailed response was requested. + public static Verbosity High { get; } = new("high"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(Verbosity left, Verbosity right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(Verbosity left, Verbosity right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is Verbosity other && Equals(other); + + /// + public bool Equals(Verbosity 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 Verbosity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, Verbosity value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(Verbosity)); + } + } +} + +/// What the user must do to recover from a failure, named as an action rather than as one client's affordance. The runtime cannot know which affordance a client offers — a slash command, a settings pane, a link — so the accompanying message stays host-agnostic and each client renders its own copy from this value. Absent when the runtime knows of no action the user can take. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct RemediationAction : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public RemediationAction(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Authenticate again with the Copilot backend. The current credential is absent, expired, or rejected. + public static RemediationAction SignIn { get; } = new("sign_in"); + + /// Authenticate as a different account. The current account exists but lacks access to the requested resource. + public static RemediationAction SwitchAccount { get; } = new("switch_account"); + + /// Inspect which account is currently authenticated before deciding what to change. + public static RemediationAction ShowAccount { get; } = new("show_account"); + + /// Review or widen the sandbox policy. The blocked path or host is named by the accompanying message or by the tool result the action arrived with. + public static RemediationAction ReviewSandboxPolicy { get; } = new("review_sandbox_policy"); + + /// Permit outbound network access in the sandbox policy. + public static RemediationAction AllowSandboxOutbound { get; } = new("allow_sandbox_outbound"); + + /// Discard conversation history back through the blocked request before continuing. + public static RemediationAction RewindConversation { get; } = new("rewind_conversation"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(RemediationAction left, RemediationAction right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(RemediationAction left, RemediationAction right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is RemediationAction other && Equals(other); + + /// + public bool Equals(RemediationAction 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 RemediationAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, RemediationAction value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RemediationAction)); + } + } +} + +/// The session mode the agent is operating in. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SessionMode : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SessionMode(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The agent is responding interactively to the user. + public static SessionMode Interactive { get; } = new("interactive"); + + /// The agent is preparing a plan before making changes. + public static SessionMode Plan { get; } = new("plan"); + + /// The agent is working autonomously toward task completion. + public static SessionMode Autopilot { get; } = new("autopilot"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionMode left, SessionMode right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionMode left, SessionMode right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SessionMode other && Equals(other); + + /// + public bool Equals(SessionMode 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 SessionMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, SessionMode value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionMode)); + } + } +} + +/// Who created the schedule: `user` (an explicit user action such as `/every` or `/after`) or `model` (the agent via the `manage_schedule` tool). Gates whether a scheduled skill that opted out of model invocation may fire: only user-created schedules may. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ScheduleOrigin : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ScheduleOrigin(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The schedule was created by an explicit user action, such as `/every` or `/after`. + public static ScheduleOrigin User { get; } = new("user"); + + /// The schedule was created by the agent via the `manage_schedule` tool. + public static ScheduleOrigin Model { get; } = new("model"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ScheduleOrigin left, ScheduleOrigin right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ScheduleOrigin left, ScheduleOrigin right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ScheduleOrigin other && Equals(other); + + /// + public bool Equals(ScheduleOrigin 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 ScheduleOrigin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ScheduleOrigin value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ScheduleOrigin)); + } + } +} + +/// The type of operation performed on the autopilot objective state file. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct AutopilotObjectiveChangedOperation : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public AutopilotObjectiveChangedOperation(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Autopilot objective state file was created for a new objective. + public static AutopilotObjectiveChangedOperation Create { get; } = new("create"); + + /// Autopilot objective state file was updated for an existing objective. + public static AutopilotObjectiveChangedOperation Update { get; } = new("update"); + + /// Autopilot objective state file was deleted or cleared. + public static AutopilotObjectiveChangedOperation Delete { get; } = new("delete"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(AutopilotObjectiveChangedOperation left, AutopilotObjectiveChangedOperation right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(AutopilotObjectiveChangedOperation left, AutopilotObjectiveChangedOperation right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is AutopilotObjectiveChangedOperation other && Equals(other); + + /// + public bool Equals(AutopilotObjectiveChangedOperation 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 AutopilotObjectiveChangedOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, AutopilotObjectiveChangedOperation value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutopilotObjectiveChangedOperation)); + } + } +} + +/// Current autopilot objective status, if one exists. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct AutopilotObjectiveChangedStatus : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public AutopilotObjectiveChangedStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Short, single-sentence description shown to the agent in canvas catalogs. - [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("description")] - public required string Description { get; set; } + /// Objective is active and can drive autopilot continuations. + public static AutopilotObjectiveChangedStatus Active { get; } = new("active"); - /// Human-readable canvas name. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Objective is paused and will not drive autopilot continuations. + public static AutopilotObjectiveChangedStatus Paused { get; } = new("paused"); - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public required string ExtensionId { get; set; } + /// Legacy objective state indicating the previous continuation cap was reached. + public static AutopilotObjectiveChangedStatus CapReached { get; } = new("cap_reached"); - /// Owning extension display name, when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("extensionName")] - public string? ExtensionName { get; set; } + /// Objective was completed by the agent. + public static AutopilotObjectiveChangedStatus Completed { get; } = new("completed"); - /// Host-local PNG path for the canvas icon, when supplied. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("icon")] - public string? Icon { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(AutopilotObjectiveChangedStatus left, AutopilotObjectiveChangedStatus right) => left.Equals(right); - /// JSON Schema for canvas open input. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("inputSchema")] - public JsonElement? InputSchema { get; set; } -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(AutopilotObjectiveChangedStatus left, AutopilotObjectiveChangedStatus right) => !(left == right); -/// Set when the underlying tools/call threw an error before returning a CallToolResult. -/// Nested data type for McpAppToolCallCompleteError. -public sealed partial class McpAppToolCallCompleteError -{ - /// Human-readable error message. - [JsonPropertyName("message")] - public required string Message { get; set; } -} + /// + public override bool Equals(object? obj) => obj is AutopilotObjectiveChangedStatus other && Equals(other); -/// MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result. -/// Nested data type for McpAppToolCallCompleteToolMetaUI. -public sealed partial class McpAppToolCallCompleteToolMetaUI -{ - /// `ui://` URI declared by the tool's `_meta.ui.resourceUri`. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resourceUri")] - public string? ResourceUri { get; set; } + /// + public bool Equals(AutopilotObjectiveChangedStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Tool visibility per SEP-1865 (typically a subset of `["model","app"]`). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("visibility")] - public string[]? Visibility { get; set; } -} + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); -/// 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. -/// Nested data type for McpAppToolCallCompleteToolMeta. -public sealed partial class McpAppToolCallCompleteToolMeta -{ - /// MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ui")] - public McpAppToolCallCompleteToolMetaUI? Ui { get; set; } + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override AutopilotObjectiveChangedStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, AutopilotObjectiveChangedStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutopilotObjectiveChangedStatus)); + } + } } -/// Routing preference used when the session model is `auto`. `fast` is an integrator-only latency preset and is not a first-party GitHub Copilot product preference. +/// Live indexed-search state for this session activation, never inferred from persisted history. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct AutoTier : IEquatable +public readonly struct IndexedSearchState : 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 AutoTier(string value) + public IndexedSearchState(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; - /// Optimize for efficiency. - public static AutoTier Efficiency { get; } = new("efficiency"); + /// Indexed search is not active for this session. + public static IndexedSearchState Disabled { get; } = new("disabled"); - /// Balance efficiency and intelligence. - public static AutoTier Balance { get; } = new("balance"); + /// Indexed-search startup is in progress. + public static IndexedSearchState Starting { get; } = new("starting"); - /// Optimize for intelligence. - public static AutoTier Intelligence { get; } = new("intelligence"); + /// The indexed-search server started successfully; its index may still be warming. + public static IndexedSearchState Enabled { get; } = new("enabled"); - /// Integrator-only preset that optimizes for latency. - public static AutoTier Fast { get; } = new("fast"); + /// The indexed-search server and its index are ready. + public static IndexedSearchState Ready { get; } = new("ready"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(AutoTier left, AutoTier right) => left.Equals(right); + /// Indexed-search startup or the active server failed. + public static IndexedSearchState Failed { get; } = new("failed"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(AutoTier left, AutoTier right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(IndexedSearchState left, IndexedSearchState right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(IndexedSearchState left, IndexedSearchState right) => !(left == right); /// - public override bool Equals(object? obj) => obj is AutoTier other && Equals(other); + public override bool Equals(object? obj) => obj is IndexedSearchState other && Equals(other); /// - public bool Equals(AutoTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(IndexedSearchState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13310,60 +14835,81 @@ public AutoTier(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 AutoTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override IndexedSearchState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, AutoTier value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, IndexedSearchState value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutoTier)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchState)); } } } -/// Hosting platform type of the repository (github or ado). +/// Configuration, policy, or workspace condition that disabled indexed search. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct WorkingDirectoryContextHostType : IEquatable +public readonly struct IndexedSearchDisabledReason : 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 WorkingDirectoryContextHostType(string value) + public IndexedSearchDisabledReason(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; - /// Repository is hosted on GitHub. - public static WorkingDirectoryContextHostType GitHub { get; } = new("github"); + /// Indexed search was explicitly disabled by the environment. + public static IndexedSearchDisabledReason UseTgrepFalse { get; } = new("use_tgrep_false"); - /// Repository is hosted on Azure DevOps. - public static WorkingDirectoryContextHostType Ado { get; } = new("ado"); + /// Search uses the external ripgrep binary instead of bundled search. + public static IndexedSearchDisabledReason UseBuiltinRipgrepFalse { get; } = new("use_builtin_ripgrep_false"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(WorkingDirectoryContextHostType left, WorkingDirectoryContextHostType right) => left.Equals(right); + /// Organization policy disables indexed search. + public static IndexedSearchDisabledReason Organization { get; } = new("organization"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(WorkingDirectoryContextHostType left, WorkingDirectoryContextHostType right) => !(left == right); + /// Authentication has not resolved organization policy. + public static IndexedSearchDisabledReason OrganizationPolicyAuthPending { get; } = new("organization_policy_auth_pending"); + + /// Organization policy could not be determined. + public static IndexedSearchDisabledReason OrganizationPolicyUnknown { get; } = new("organization_policy_unknown"); + + /// The workspace uses a virtualized or network filesystem. + public static IndexedSearchDisabledReason VirtualFilesystem { get; } = new("virtual_filesystem"); + + /// The workspace is inside a Windows cloud-sync root. + public static IndexedSearchDisabledReason CloudSyncRoot { get; } = new("cloud_sync_root"); + + /// The Windows cloud-sync safety check failed. + public static IndexedSearchDisabledReason CloudSyncDetectionFailed { get; } = new("cloud_sync_detection_failed"); + + /// The workspace is not available on the runtime's local filesystem. + public static IndexedSearchDisabledReason WorkspaceNotLocal { get; } = new("workspace_not_local"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(IndexedSearchDisabledReason left, IndexedSearchDisabledReason right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(IndexedSearchDisabledReason left, IndexedSearchDisabledReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is WorkingDirectoryContextHostType other && Equals(other); + public override bool Equals(object? obj) => obj is IndexedSearchDisabledReason other && Equals(other); /// - public bool Equals(WorkingDirectoryContextHostType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(IndexedSearchDisabledReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13371,60 +14917,72 @@ public WorkingDirectoryContextHostType(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 WorkingDirectoryContextHostType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override IndexedSearchDisabledReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, WorkingDirectoryContextHostType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, IndexedSearchDisabledReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(WorkingDirectoryContextHostType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchDisabledReason)); } } } -/// Allowed values for the `ContextTier` enumeration. +/// Result of an indexed-search startup attempt. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ContextTier : IEquatable +public readonly struct IndexedSearchOutcome : 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 ContextTier(string value) + public IndexedSearchOutcome(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 ContextTier Default { get; } = new("default"); + /// A new indexed-search server was started. + public static IndexedSearchOutcome Started { get; } = new("started"); - /// Extended context tier with a larger context window. - public static ContextTier LongContext { get; } = new("long_context"); + /// The repository has too few files for automatic indexing. + public static IndexedSearchOutcome SkippedBelowThreshold { get; } = new("skipped_below_threshold"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ContextTier left, ContextTier right) => left.Equals(right); + /// No Git repository was found and indexing was not forced. + public static IndexedSearchOutcome SkippedNoGitroot { get; } = new("skipped_no_gitroot"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ContextTier left, ContextTier right) => !(left == right); + /// Configuration, policy, or workspace safety disabled indexing. + public static IndexedSearchOutcome SkippedDisabled { get; } = new("skipped_disabled"); + + /// An existing indexed-search server was reused. + public static IndexedSearchOutcome ReusedExisting { get; } = new("reused_existing"); + + /// The startup attempt failed. + public static IndexedSearchOutcome Failed { get; } = new("failed"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(IndexedSearchOutcome left, IndexedSearchOutcome right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(IndexedSearchOutcome left, IndexedSearchOutcome right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ContextTier other && Equals(other); + public override bool Equals(object? obj) => obj is IndexedSearchOutcome other && Equals(other); /// - public bool Equals(ContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(IndexedSearchOutcome other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13432,63 +14990,63 @@ public ContextTier(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 ContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override IndexedSearchOutcome Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ContextTier value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, IndexedSearchOutcome value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ContextTier)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchOutcome)); } } } -/// Reasoning summary mode used for model calls, if applicable (e.g. "none", "concise", "detailed"). +/// Category of an indexed-search server failure. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ReasoningSummary : IEquatable +public readonly struct IndexedSearchErrorType : 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 ReasoningSummary(string value) + public IndexedSearchErrorType(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; - /// Do not request reasoning summaries from the model. - public static ReasoningSummary None { get; } = new("none"); + /// The indexed-search server could not be spawned. + public static IndexedSearchErrorType SpawnError { get; } = new("spawn_error"); - /// Request a concise summary of the model's reasoning. - public static ReasoningSummary Concise { get; } = new("concise"); + /// The indexed-search server exited unexpectedly. + public static IndexedSearchErrorType UnexpectedExit { get; } = new("unexpected_exit"); - /// Request a detailed summary of the model's reasoning. - public static ReasoningSummary Detailed { get; } = new("detailed"); + /// The indexed-search server was terminated by a signal. + public static IndexedSearchErrorType KilledBySignal { get; } = new("killed_by_signal"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ReasoningSummary left, ReasoningSummary right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(IndexedSearchErrorType left, IndexedSearchErrorType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ReasoningSummary left, ReasoningSummary right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(IndexedSearchErrorType left, IndexedSearchErrorType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ReasoningSummary other && Equals(other); + public override bool Equals(object? obj) => obj is IndexedSearchErrorType other && Equals(other); /// - public bool Equals(ReasoningSummary other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(IndexedSearchErrorType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13496,63 +15054,60 @@ public ReasoningSummary(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 ReasoningSummary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override IndexedSearchErrorType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ReasoningSummary value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, IndexedSearchErrorType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ReasoningSummary)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchErrorType)); } } } -/// Output verbosity level used for supported model calls (e.g. "low", "medium", "high"). +/// Phase of an incremental indexed-search update. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct Verbosity : IEquatable +public readonly struct IndexedSearchIncrementalPhase : 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 Verbosity(string value) + public IndexedSearchIncrementalPhase(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; - /// A terse response was requested. - public static Verbosity Low { get; } = new("low"); - - /// A medium amount of response detail was requested. - public static Verbosity Medium { get; } = new("medium"); + /// A workspace scan found changes to index. + public static IndexedSearchIncrementalPhase ChangesDetected { get; } = new("changes_detected"); - /// A more detailed response was requested. - public static Verbosity High { get; } = new("high"); + /// The incremental index update completed. + public static IndexedSearchIncrementalPhase Updated { get; } = new("updated"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(Verbosity left, Verbosity right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(IndexedSearchIncrementalPhase left, IndexedSearchIncrementalPhase right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(Verbosity left, Verbosity right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(IndexedSearchIncrementalPhase left, IndexedSearchIncrementalPhase right) => !(left == right); /// - public override bool Equals(object? obj) => obj is Verbosity other && Equals(other); + public override bool Equals(object? obj) => obj is IndexedSearchIncrementalPhase other && Equals(other); /// - public bool Equals(Verbosity other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(IndexedSearchIncrementalPhase other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13560,69 +15115,93 @@ public Verbosity(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 Verbosity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override IndexedSearchIncrementalPhase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, Verbosity value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, IndexedSearchIncrementalPhase value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(Verbosity)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchIncrementalPhase)); } } } -/// What the user must do to recover from a failure, named as an action rather than as one client's affordance. The runtime cannot know which affordance a client offers — a slash command, a settings pane, a link — so the accompanying message stays host-agnostic and each client renders its own copy from this value. Absent when the runtime knows of no action the user can take. +/// Origin of an effective session model change. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct RemediationAction : IEquatable +public readonly struct ModelChangeSource : 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 RemediationAction(string value) + public ModelChangeSource(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; - /// Authenticate again with the Copilot backend. The current credential is absent, expired, or rejected. - public static RemediationAction SignIn { get; } = new("sign_in"); + /// The user selected a model directly with `/model <id>`. + public static ModelChangeSource ModelCommand { get; } = new("model_command"); - /// Authenticate as a different account. The current account exists but lacks access to the requested resource. - public static RemediationAction SwitchAccount { get; } = new("switch_account"); + /// The user selected the model with `/settings`. + public static ModelChangeSource SettingsCommand { get; } = new("settings_command"); - /// Inspect which account is currently authenticated before deciding what to change. - public static RemediationAction ShowAccount { get; } = new("show_account"); + /// The user selected the model with the `/config` alias. + public static ModelChangeSource ConfigCommand { get; } = new("config_command"); - /// Review or widen the sandbox policy. The blocked path or host is named by the accompanying message or by the tool result the action arrived with. - public static RemediationAction ReviewSandboxPolicy { get; } = new("review_sandbox_policy"); + /// The user selected the model in the model picker, including the picker opened by bare `/model`. + public static ModelChangeSource ModelPicker { get; } = new("model_picker"); - /// Permit outbound network access in the sandbox policy. - public static RemediationAction AllowSandboxOutbound { get; } = new("allow_sandbox_outbound"); + /// Organization-managed settings selected the model. + public static ModelChangeSource ManagedSettings { get; } = new("managed_settings"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(RemediationAction left, RemediationAction right) => left.Equals(right); + /// Repository settings selected the model. + public static ModelChangeSource RepoSettings { get; } = new("repo_settings"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(RemediationAction left, RemediationAction right) => !(left == right); + /// Startup model resolution selected the model. + public static ModelChangeSource Startup { get; } = new("startup"); + + /// Selecting an agent selected its configured model. + public static ModelChangeSource Agent { get; } = new("agent"); + + /// Entering, leaving, or reconfiguring plan mode selected the model. + public static ModelChangeSource PlanMode { get; } = new("plan_mode"); + + /// The runtime selected the model automatically, such as rate-limit recovery or refusal fallback. + public static ModelChangeSource Automatic { get; } = new("automatic"); + + /// The user selected the promoted model from the changeboarding card or its keyboard shortcut. + public static ModelChangeSource ChangeboardingShortcut { get; } = new("changeboarding_shortcut"); + + /// An SDK or RPC caller selected the model. + public static ModelChangeSource Sdk { get; } = new("sdk"); + + /// The user accepted a CAPI-issued Auto tier recommendation. + public static ModelChangeSource AutoTierRecommendation { get; } = new("auto_tier_recommendation"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelChangeSource left, ModelChangeSource right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelChangeSource left, ModelChangeSource right) => !(left == right); /// - public override bool Equals(object? obj) => obj is RemediationAction other && Equals(other); + public override bool Equals(object? obj) => obj is ModelChangeSource other && Equals(other); /// - public bool Equals(RemediationAction other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ModelChangeSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13630,63 +15209,57 @@ public RemediationAction(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 RemediationAction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ModelChangeSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, RemediationAction value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ModelChangeSource value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RemediationAction)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelChangeSource)); } } } -/// The session mode the agent is operating in. +/// Why the session no longer has an explicitly selected model. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionMode : IEquatable +public readonly struct ModelDeselectedReason : 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 SessionMode(string value) + public ModelDeselectedReason(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; - /// The agent is responding interactively to the user. - public static SessionMode Interactive { get; } = new("interactive"); - - /// The agent is preparing a plan before making changes. - public static SessionMode Plan { get; } = new("plan"); - - /// The agent is working autonomously toward task completion. - public static SessionMode Autopilot { get; } = new("autopilot"); + /// A host-managed provider snapshot no longer publishes the selected model. + public static ModelDeselectedReason ProviderWithdrawn { get; } = new("provider_withdrawn"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionMode left, SessionMode right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelDeselectedReason left, ModelDeselectedReason right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionMode left, SessionMode right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelDeselectedReason left, ModelDeselectedReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionMode other && Equals(other); + public override bool Equals(object? obj) => obj is ModelDeselectedReason other && Equals(other); /// - public bool Equals(SessionMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ModelDeselectedReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13694,124 +15267,130 @@ public SessionMode(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 SessionMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ModelDeselectedReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionMode value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ModelDeselectedReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionMode)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelDeselectedReason)); } } } -/// Who created the schedule: `user` (an explicit user action such as `/every` or `/after`) or `model` (the agent via the `manage_schedule` tool). Gates whether a scheduled skill that opted out of model invocation may fire: only user-created schedules may. +/// Enabled Auto preferences that Copilot API can recommend. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ScheduleOrigin : IEquatable +public readonly struct RecommendedAutoTier : 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 ScheduleOrigin(string value) + public RecommendedAutoTier(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; - /// The schedule was created by an explicit user action, such as `/every` or `/after`. - public static ScheduleOrigin User { get; } = new("user"); + /// Optimize for efficiency. + public static RecommendedAutoTier Efficiency { get; } = new("efficiency"); - /// The schedule was created by the agent via the `manage_schedule` tool. - public static ScheduleOrigin Model { get; } = new("model"); + /// Balance efficiency and intelligence. + public static RecommendedAutoTier Balance { get; } = new("balance"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ScheduleOrigin left, ScheduleOrigin right) => left.Equals(right); + /// Optimize for intelligence. + public static RecommendedAutoTier Intelligence { get; } = new("intelligence"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ScheduleOrigin left, ScheduleOrigin right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(RecommendedAutoTier left, RecommendedAutoTier right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(RecommendedAutoTier left, RecommendedAutoTier right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ScheduleOrigin other && Equals(other); + public override bool Equals(object? obj) => obj is RecommendedAutoTier other && Equals(other); /// - public bool Equals(ScheduleOrigin other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(RecommendedAutoTier other) => string.Equals(Value, other.Value, StringComparison.Ordinal); /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(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 ScheduleOrigin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override RecommendedAutoTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ScheduleOrigin value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, RecommendedAutoTier value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ScheduleOrigin)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RecommendedAutoTier)); } } } -/// The type of operation performed on the autopilot objective state file. +/// Terminal reason an Auto preference activation failed. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct AutopilotObjectiveChangedOperation : IEquatable +public readonly struct AutoTierSwitchFailureReason : 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 AutopilotObjectiveChangedOperation(string value) + public AutoTierSwitchFailureReason(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; - /// Autopilot objective state file was created for a new objective. - public static AutopilotObjectiveChangedOperation Create { get; } = new("create"); + /// The candidate model was rejected by model policy. + public static AutoTierSwitchFailureReason PolicyRejected { get; } = new("policy_rejected"); - /// Autopilot objective state file was updated for an existing objective. - public static AutopilotObjectiveChangedOperation Update { get; } = new("update"); + /// The Auto routing request failed or returned an unusable response. + public static AutoTierSwitchFailureReason RequestFailed { get; } = new("request_failed"); - /// Autopilot objective state file was deleted or cleared. - public static AutopilotObjectiveChangedOperation Delete { get; } = new("delete"); + /// The runtime could not prepare the Auto routing request. + public static AutoTierSwitchFailureReason SetupFailed { get; } = new("setup_failed"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(AutopilotObjectiveChangedOperation left, AutopilotObjectiveChangedOperation right) => left.Equals(right); + /// The provider does not support Auto routing. + public static AutoTierSwitchFailureReason Unsupported { get; } = new("unsupported"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(AutopilotObjectiveChangedOperation left, AutopilotObjectiveChangedOperation right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(AutoTierSwitchFailureReason left, AutoTierSwitchFailureReason right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(AutoTierSwitchFailureReason left, AutoTierSwitchFailureReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is AutopilotObjectiveChangedOperation other && Equals(other); + public override bool Equals(object? obj) => obj is AutoTierSwitchFailureReason other && Equals(other); /// - public bool Equals(AutopilotObjectiveChangedOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(AutoTierSwitchFailureReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13819,66 +15398,64 @@ public AutopilotObjectiveChangedOperation(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 AutopilotObjectiveChangedOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override AutoTierSwitchFailureReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, AutopilotObjectiveChangedOperation value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, AutoTierSwitchFailureReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutopilotObjectiveChangedOperation)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutoTierSwitchFailureReason)); } } } -/// Current autopilot objective status, if one exists. +/// Permission mode for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct AutopilotObjectiveChangedStatus : IEquatable +public readonly struct PermissionMode : 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 AutopilotObjectiveChangedStatus(string value) + public PermissionMode(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; - /// Objective is active and can drive autopilot continuations. - public static AutopilotObjectiveChangedStatus Active { get; } = new("active"); - - /// Objective is paused and will not drive autopilot continuations. - public static AutopilotObjectiveChangedStatus Paused { get; } = new("paused"); + /// Permission requests follow the normal approval flow. + public static PermissionMode Manual { get; } = new("manual"); - /// Legacy objective state indicating the previous continuation cap was reached. - public static AutopilotObjectiveChangedStatus CapReached { get; } = new("cap_reached"); + /// Permission requests include an LLM safety recommendation; clients may automatically approve requests judged acceptable. + public static PermissionMode Assisted { get; } = new("assisted"); - /// Objective was completed by the agent. - public static AutopilotObjectiveChangedStatus Completed { get; } = new("completed"); + /// Tool, path, and URL permission requests are automatically approved. + public static PermissionMode AllowAll { get; } = new("allow-all"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(AutopilotObjectiveChangedStatus left, AutopilotObjectiveChangedStatus right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(PermissionMode left, PermissionMode right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(AutopilotObjectiveChangedStatus left, AutopilotObjectiveChangedStatus right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(PermissionMode left, PermissionMode right) => !(left == right); /// - public override bool Equals(object? obj) => obj is AutopilotObjectiveChangedStatus other && Equals(other); + public override bool Equals(object? obj) => obj is PermissionMode other && Equals(other); /// - public bool Equals(AutopilotObjectiveChangedStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(PermissionMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13886,69 +15463,63 @@ public AutopilotObjectiveChangedStatus(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 AutopilotObjectiveChangedStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PermissionMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, AutopilotObjectiveChangedStatus value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PermissionMode value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutopilotObjectiveChangedStatus)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionMode)); } } } -/// Live indexed-search state for this session activation, never inferred from persisted history. +/// The type of operation performed on the plan file. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct IndexedSearchState : IEquatable +public readonly struct PlanChangedOperation : 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 IndexedSearchState(string value) + public PlanChangedOperation(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; - /// Indexed search is not active for this session. - public static IndexedSearchState Disabled { get; } = new("disabled"); - - /// Indexed-search startup is in progress. - public static IndexedSearchState Starting { get; } = new("starting"); - - /// The indexed-search server started successfully; its index may still be warming. - public static IndexedSearchState Enabled { get; } = new("enabled"); + /// The plan file was created. + public static PlanChangedOperation Create { get; } = new("create"); - /// The indexed-search server and its index are ready. - public static IndexedSearchState Ready { get; } = new("ready"); + /// The plan file was updated. + public static PlanChangedOperation Update { get; } = new("update"); - /// Indexed-search startup or the active server failed. - public static IndexedSearchState Failed { get; } = new("failed"); + /// The plan file was deleted. + public static PlanChangedOperation Delete { get; } = new("delete"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(IndexedSearchState left, IndexedSearchState right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(PlanChangedOperation left, PlanChangedOperation right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(IndexedSearchState left, IndexedSearchState right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(PlanChangedOperation left, PlanChangedOperation right) => !(left == right); /// - public override bool Equals(object? obj) => obj is IndexedSearchState other && Equals(other); + public override bool Equals(object? obj) => obj is PlanChangedOperation other && Equals(other); /// - public bool Equals(IndexedSearchState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(PlanChangedOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -13956,81 +15527,60 @@ public IndexedSearchState(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 IndexedSearchState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override PlanChangedOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, IndexedSearchState value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, PlanChangedOperation value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchState)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PlanChangedOperation)); } } } -/// Configuration, policy, or workspace condition that disabled indexed search. +/// Whether the file was newly created or updated. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct IndexedSearchDisabledReason : IEquatable +public readonly struct WorkspaceFileChangedOperation : 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 IndexedSearchDisabledReason(string value) + public WorkspaceFileChangedOperation(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; - /// Indexed search was explicitly disabled by the environment. - public static IndexedSearchDisabledReason UseTgrepFalse { get; } = new("use_tgrep_false"); - - /// Search uses the external ripgrep binary instead of bundled search. - public static IndexedSearchDisabledReason UseBuiltinRipgrepFalse { get; } = new("use_builtin_ripgrep_false"); - - /// Organization policy disables indexed search. - public static IndexedSearchDisabledReason Organization { get; } = new("organization"); - - /// Authentication has not resolved organization policy. - public static IndexedSearchDisabledReason OrganizationPolicyAuthPending { get; } = new("organization_policy_auth_pending"); - - /// Organization policy could not be determined. - public static IndexedSearchDisabledReason OrganizationPolicyUnknown { get; } = new("organization_policy_unknown"); - - /// The workspace uses a virtualized or network filesystem. - public static IndexedSearchDisabledReason VirtualFilesystem { get; } = new("virtual_filesystem"); - - /// The workspace is inside a Windows cloud-sync root. - public static IndexedSearchDisabledReason CloudSyncRoot { get; } = new("cloud_sync_root"); - - /// The Windows cloud-sync safety check failed. - public static IndexedSearchDisabledReason CloudSyncDetectionFailed { get; } = new("cloud_sync_detection_failed"); + /// The workspace file was created. + public static WorkspaceFileChangedOperation Create { get; } = new("create"); - /// The workspace is not available on the runtime's local filesystem. - public static IndexedSearchDisabledReason WorkspaceNotLocal { get; } = new("workspace_not_local"); + /// The workspace file was updated. + public static WorkspaceFileChangedOperation Update { get; } = new("update"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(IndexedSearchDisabledReason left, IndexedSearchDisabledReason right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(WorkspaceFileChangedOperation left, WorkspaceFileChangedOperation right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(IndexedSearchDisabledReason left, IndexedSearchDisabledReason right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(WorkspaceFileChangedOperation left, WorkspaceFileChangedOperation right) => !(left == right); /// - public override bool Equals(object? obj) => obj is IndexedSearchDisabledReason other && Equals(other); + public override bool Equals(object? obj) => obj is WorkspaceFileChangedOperation other && Equals(other); /// - public bool Equals(IndexedSearchDisabledReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(WorkspaceFileChangedOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14038,72 +15588,60 @@ public IndexedSearchDisabledReason(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 IndexedSearchDisabledReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override WorkspaceFileChangedOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, IndexedSearchDisabledReason value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, WorkspaceFileChangedOperation value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchDisabledReason)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(WorkspaceFileChangedOperation)); } } } -/// Result of an indexed-search startup attempt. +/// Origin type of the session being handed off. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct IndexedSearchOutcome : IEquatable +public readonly struct HandoffSourceType : 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 IndexedSearchOutcome(string value) + public HandoffSourceType(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; - /// A new indexed-search server was started. - public static IndexedSearchOutcome Started { get; } = new("started"); - - /// The repository has too few files for automatic indexing. - public static IndexedSearchOutcome SkippedBelowThreshold { get; } = new("skipped_below_threshold"); - - /// No Git repository was found and indexing was not forced. - public static IndexedSearchOutcome SkippedNoGitroot { get; } = new("skipped_no_gitroot"); - - /// Configuration, policy, or workspace safety disabled indexing. - public static IndexedSearchOutcome SkippedDisabled { get; } = new("skipped_disabled"); - - /// An existing indexed-search server was reused. - public static IndexedSearchOutcome ReusedExisting { get; } = new("reused_existing"); + /// The handoff originated from a remote session. + public static HandoffSourceType Remote { get; } = new("remote"); - /// The startup attempt failed. - public static IndexedSearchOutcome Failed { get; } = new("failed"); + /// The handoff originated from a local session. + public static HandoffSourceType Local { get; } = new("local"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(IndexedSearchOutcome left, IndexedSearchOutcome right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(HandoffSourceType left, HandoffSourceType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(IndexedSearchOutcome left, IndexedSearchOutcome right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(HandoffSourceType left, HandoffSourceType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is IndexedSearchOutcome other && Equals(other); + public override bool Equals(object? obj) => obj is HandoffSourceType other && Equals(other); /// - public bool Equals(IndexedSearchOutcome other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(HandoffSourceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14111,63 +15649,63 @@ public IndexedSearchOutcome(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 IndexedSearchOutcome Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override HandoffSourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, IndexedSearchOutcome value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, HandoffSourceType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchOutcome)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HandoffSourceType)); } } } -/// Category of an indexed-search server failure. +/// Whether the accumulated numeric AI-credit subtotal covers the observed calls. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct IndexedSearchErrorType : IEquatable +public readonly struct AiCreditsStatus : 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 IndexedSearchErrorType(string value) + public AiCreditsStatus(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; - /// The indexed-search server could not be spawned. - public static IndexedSearchErrorType SpawnError { get; } = new("spawn_error"); + /// Every observed call supplied an AI-credit amount, including an explicit zero. + public static AiCreditsStatus Complete { get; } = new("complete"); - /// The indexed-search server exited unexpectedly. - public static IndexedSearchErrorType UnexpectedExit { get; } = new("unexpected_exit"); + /// Some calls supplied amounts and some did not; the numeric value is only a reported subtotal. + public static AiCreditsStatus Partial { get; } = new("partial"); - /// The indexed-search server was terminated by a signal. - public static IndexedSearchErrorType KilledBySignal { get; } = new("killed_by_signal"); + /// No AI-credit amount was reported for the observed calls. Numeric zero is not a zero-cost claim. + public static AiCreditsStatus Unavailable { get; } = new("unavailable"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(IndexedSearchErrorType left, IndexedSearchErrorType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(AiCreditsStatus left, AiCreditsStatus right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(IndexedSearchErrorType left, IndexedSearchErrorType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(AiCreditsStatus left, AiCreditsStatus right) => !(left == right); /// - public override bool Equals(object? obj) => obj is IndexedSearchErrorType other && Equals(other); + public override bool Equals(object? obj) => obj is AiCreditsStatus other && Equals(other); /// - public bool Equals(IndexedSearchErrorType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(AiCreditsStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14175,60 +15713,61 @@ public IndexedSearchErrorType(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 IndexedSearchErrorType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override AiCreditsStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, IndexedSearchErrorType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, AiCreditsStatus value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchErrorType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AiCreditsStatus)); } } } -/// Phase of an incremental indexed-search update. +/// The neutral kind of a model provider — the model analog of `AccountKind`. A model provider is the live, entitled source a model came from; central code never branches on this beyond a single dispatch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct IndexedSearchIncrementalPhase : IEquatable +public readonly struct ModelProviderKind : 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 IndexedSearchIncrementalPhase(string value) + public ModelProviderKind(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; - /// A workspace scan found changes to index. - public static IndexedSearchIncrementalPhase ChangesDetected { get; } = new("changes_detected"); + /// GitHub Copilot / CAPI models, spawned by a github-resolving account that holds a Copilot seat. + public static ModelProviderKind Copilot { get; } = new("copilot"); - /// The incremental index update completed. - public static IndexedSearchIncrementalPhase Updated { get; } = new("updated"); + /// Microsoft 365 Copilot (Loki) inference models, spawned by a resolvable Entra-derived Loki account. + public static ModelProviderKind Loki { get; } = new("loki"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(IndexedSearchIncrementalPhase left, IndexedSearchIncrementalPhase right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelProviderKind left, ModelProviderKind right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(IndexedSearchIncrementalPhase left, IndexedSearchIncrementalPhase right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelProviderKind left, ModelProviderKind right) => !(left == right); /// - public override bool Equals(object? obj) => obj is IndexedSearchIncrementalPhase other && Equals(other); + public override bool Equals(object? obj) => obj is ModelProviderKind other && Equals(other); /// - public bool Equals(IndexedSearchIncrementalPhase other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ModelProviderKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14236,93 +15775,60 @@ public IndexedSearchIncrementalPhase(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 IndexedSearchIncrementalPhase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ModelProviderKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, IndexedSearchIncrementalPhase value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ModelProviderKind value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(IndexedSearchIncrementalPhase)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelProviderKind)); } } } -/// Origin of an effective session model change. +/// Whether the session ended normally ("routine") or due to a crash/fatal error ("error"). [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ModelChangeSource : IEquatable +public readonly struct ShutdownType : 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 ModelChangeSource(string value) + public ShutdownType(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; - /// The user selected a model directly with `/model <id>`. - public static ModelChangeSource ModelCommand { get; } = new("model_command"); - - /// The user selected the model with `/settings`. - public static ModelChangeSource SettingsCommand { get; } = new("settings_command"); - - /// The user selected the model with the `/config` alias. - public static ModelChangeSource ConfigCommand { get; } = new("config_command"); - - /// The user selected the model in the model picker, including the picker opened by bare `/model`. - public static ModelChangeSource ModelPicker { get; } = new("model_picker"); - - /// Organization-managed settings selected the model. - public static ModelChangeSource ManagedSettings { get; } = new("managed_settings"); - - /// Repository settings selected the model. - public static ModelChangeSource RepoSettings { get; } = new("repo_settings"); - - /// Startup model resolution selected the model. - public static ModelChangeSource Startup { get; } = new("startup"); - - /// Selecting an agent selected its configured model. - public static ModelChangeSource Agent { get; } = new("agent"); - - /// Entering, leaving, or reconfiguring plan mode selected the model. - public static ModelChangeSource PlanMode { get; } = new("plan_mode"); - - /// The runtime selected the model automatically, such as rate-limit recovery or refusal fallback. - public static ModelChangeSource Automatic { get; } = new("automatic"); - - /// The user selected the promoted model from the changeboarding card or its keyboard shortcut. - public static ModelChangeSource ChangeboardingShortcut { get; } = new("changeboarding_shortcut"); - - /// An SDK or RPC caller selected the model. - public static ModelChangeSource Sdk { get; } = new("sdk"); + /// The session ended normally. + public static ShutdownType Routine { get; } = new("routine"); - /// The user accepted a CAPI-issued Auto tier recommendation. - public static ModelChangeSource AutoTierRecommendation { get; } = new("auto_tier_recommendation"); + /// The session ended because of a crash or fatal error. + public static ShutdownType Error { get; } = new("error"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ModelChangeSource left, ModelChangeSource right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ShutdownType left, ShutdownType right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ModelChangeSource left, ModelChangeSource right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ShutdownType left, ShutdownType right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ModelChangeSource other && Equals(other); + public override bool Equals(object? obj) => obj is ShutdownType other && Equals(other); /// - public bool Equals(ModelChangeSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ShutdownType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14330,57 +15836,69 @@ public ModelChangeSource(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 ModelChangeSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ShutdownType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ModelChangeSource value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ShutdownType value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelChangeSource)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShutdownType)); } } } -/// Why the session no longer has an explicitly selected model. +/// Access policy reported by the quota service. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ModelDeselectedReason : IEquatable +public readonly struct ProviderQuotaAccessState : 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 ModelDeselectedReason(string value) + public ProviderQuotaAccessState(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; - /// A host-managed provider snapshot no longer publishes the selected model. - public static ModelDeselectedReason ProviderWithdrawn { get; } = new("provider_withdrawn"); + /// Access is allowed. + public static ProviderQuotaAccessState Allowed { get; } = new("allowed"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ModelDeselectedReason left, ModelDeselectedReason right) => left.Equals(right); + /// Access is denied. + public static ProviderQuotaAccessState Denied { get; } = new("denied"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ModelDeselectedReason left, ModelDeselectedReason right) => !(left == right); + /// Quota is not required for this access. + public static ProviderQuotaAccessState NotRequired { get; } = new("not_required"); + + /// The service did not supply a recognized access state. + public static ProviderQuotaAccessState Unknown { get; } = new("unknown"); + + /// Client-only compatibility placeholder when acquisitionStatus is unavailable or failed; not an observed service verdict. + public static ProviderQuotaAccessState Unavailable { get; } = new("unavailable"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaAccessState left, ProviderQuotaAccessState right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaAccessState left, ProviderQuotaAccessState right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ModelDeselectedReason other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderQuotaAccessState other && Equals(other); /// - public bool Equals(ModelDeselectedReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderQuotaAccessState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14388,63 +15906,63 @@ public ModelDeselectedReason(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 ModelDeselectedReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderQuotaAccessState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ModelDeselectedReason value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderQuotaAccessState value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelDeselectedReason)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaAccessState)); } } } -/// Auto preferences that Copilot API can recommend. +/// Acquisition state, independent of the service's business access/capacity verdict. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct RecommendedAutoTier : IEquatable +public readonly struct ProviderQuotaAcquisitionStatus : 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 RecommendedAutoTier(string value) + public ProviderQuotaAcquisitionStatus(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; - /// Optimize for efficiency. - public static RecommendedAutoTier Efficiency { get; } = new("efficiency"); + /// A service quota observation was received. + public static ProviderQuotaAcquisitionStatus Succeeded { get; } = new("succeeded"); - /// Balance efficiency and intelligence. - public static RecommendedAutoTier Balance { get; } = new("balance"); + /// No service snapshot is available for this caller or surface. + public static ProviderQuotaAcquisitionStatus Unavailable { get; } = new("unavailable"); - /// Optimize for intelligence. - public static RecommendedAutoTier Intelligence { get; } = new("intelligence"); + /// Acquisition failed; inspect httpStatus/acquisitionError without inferring a business verdict. + public static ProviderQuotaAcquisitionStatus Failed { get; } = new("failed"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(RecommendedAutoTier left, RecommendedAutoTier right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaAcquisitionStatus left, ProviderQuotaAcquisitionStatus right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(RecommendedAutoTier left, RecommendedAutoTier right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaAcquisitionStatus left, ProviderQuotaAcquisitionStatus right) => !(left == right); /// - public override bool Equals(object? obj) => obj is RecommendedAutoTier other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderQuotaAcquisitionStatus other && Equals(other); /// - public bool Equals(RecommendedAutoTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderQuotaAcquisitionStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14452,66 +15970,75 @@ public RecommendedAutoTier(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 RecommendedAutoTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderQuotaAcquisitionStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, RecommendedAutoTier value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderQuotaAcquisitionStatus value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RecommendedAutoTier)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaAcquisitionStatus)); } } } -/// Terminal reason an Auto preference activation failed. +/// Capacity is independent of whether a numeric balance was supplied. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct AutoTierSwitchFailureReason : IEquatable +public readonly struct ProviderQuotaCapacityState : 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 AutoTierSwitchFailureReason(string value) + public ProviderQuotaCapacityState(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; - /// The candidate model was rejected by model policy. - public static AutoTierSwitchFailureReason PolicyRejected { get; } = new("policy_rejected"); + /// Capacity is available. + public static ProviderQuotaCapacityState Available { get; } = new("available"); - /// The Auto routing request failed or returned an unusable response. - public static AutoTierSwitchFailureReason RequestFailed { get; } = new("request_failed"); + /// The service explicitly reports exhaustion. + public static ProviderQuotaCapacityState Exhausted { get; } = new("exhausted"); - /// The runtime could not prepare the Auto routing request. - public static AutoTierSwitchFailureReason SetupFailed { get; } = new("setup_failed"); + /// The reported entitlement is unlimited. + public static ProviderQuotaCapacityState Unlimited { get; } = new("unlimited"); - /// The provider does not support Auto routing. - public static AutoTierSwitchFailureReason Unsupported { get; } = new("unsupported"); + /// No billable quota is required. + public static ProviderQuotaCapacityState NotRequired { get; } = new("not_required"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(AutoTierSwitchFailureReason left, AutoTierSwitchFailureReason right) => left.Equals(right); + /// The service reports that capacity is not applicable. + public static ProviderQuotaCapacityState NotApplicable { get; } = new("not_applicable"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(AutoTierSwitchFailureReason left, AutoTierSwitchFailureReason right) => !(left == right); + /// No recognized capacity state was supplied. + public static ProviderQuotaCapacityState Unknown { get; } = new("unknown"); + + /// Client-only compatibility placeholder when acquisitionStatus is unavailable or failed; not an observed service verdict. + public static ProviderQuotaCapacityState Unavailable { get; } = new("unavailable"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaCapacityState left, ProviderQuotaCapacityState right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaCapacityState left, ProviderQuotaCapacityState right) => !(left == right); /// - public override bool Equals(object? obj) => obj is AutoTierSwitchFailureReason other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderQuotaCapacityState other && Equals(other); /// - public bool Equals(AutoTierSwitchFailureReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderQuotaCapacityState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14519,64 +16046,60 @@ public AutoTierSwitchFailureReason(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 AutoTierSwitchFailureReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderQuotaCapacityState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, AutoTierSwitchFailureReason value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderQuotaCapacityState value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutoTierSwitchFailureReason)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaCapacityState)); } } } -/// Permission mode for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +/// Identity scope of a monthly usage reading. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PermissionMode : IEquatable +public readonly struct ProviderMonthlyUsageScope : 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 PermissionMode(string value) + public ProviderMonthlyUsageScope(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; - /// Permission requests follow the normal approval flow. - public static PermissionMode Manual { get; } = new("manual"); - - /// Permission requests include an LLM safety recommendation; clients may automatically approve requests judged acceptable. - public static PermissionMode Assisted { get; } = new("assisted"); + /// Consumption of the authenticated user within the parent observation's service and returned cycle. + public static ProviderMonthlyUsageScope User { get; } = new("user"); - /// Tool, path, and URL permission requests are automatically approved. - public static PermissionMode AllowAll { get; } = new("allow-all"); + /// The service did not establish a recognized usage scope. + public static ProviderMonthlyUsageScope Unknown { get; } = new("unknown"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(PermissionMode left, PermissionMode right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderMonthlyUsageScope left, ProviderMonthlyUsageScope right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PermissionMode left, PermissionMode right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderMonthlyUsageScope left, ProviderMonthlyUsageScope right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PermissionMode other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderMonthlyUsageScope other && Equals(other); /// - public bool Equals(PermissionMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderMonthlyUsageScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14584,63 +16107,66 @@ public PermissionMode(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 PermissionMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderMonthlyUsageScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, PermissionMode value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderMonthlyUsageScope value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionMode)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderMonthlyUsageScope)); } } } -/// The type of operation performed on the plan file. +/// Availability of a service's monthly consumption reading. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct PlanChangedOperation : IEquatable +public readonly struct ProviderMonthlyUsageState : 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 PlanChangedOperation(string value) + public ProviderMonthlyUsageState(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; - /// The plan file was created. - public static PlanChangedOperation Create { get; } = new("create"); + /// The service reported a usable consumption reading, including an explicit zero. + public static ProviderMonthlyUsageState Available { get; } = new("available"); - /// The plan file was updated. - public static PlanChangedOperation Update { get; } = new("update"); + /// The service found no usage policy; no consumption amount is known. + public static ProviderMonthlyUsageState NoPolicy { get; } = new("no_policy"); - /// The plan file was deleted. - public static PlanChangedOperation Delete { get; } = new("delete"); + /// The read failed or its data could not be used; consumption is unknown. + public static ProviderMonthlyUsageState Unavailable { get; } = new("unavailable"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(PlanChangedOperation left, PlanChangedOperation right) => left.Equals(right); + /// The service reported an unrecognized usage state. + public static ProviderMonthlyUsageState Unknown { get; } = new("unknown"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(PlanChangedOperation left, PlanChangedOperation right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderMonthlyUsageState left, ProviderMonthlyUsageState right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderMonthlyUsageState left, ProviderMonthlyUsageState right) => !(left == right); /// - public override bool Equals(object? obj) => obj is PlanChangedOperation other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderMonthlyUsageState other && Equals(other); /// - public bool Equals(PlanChangedOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderMonthlyUsageState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14648,60 +16174,66 @@ public PlanChangedOperation(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 PlanChangedOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderMonthlyUsageState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, PlanChangedOperation value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderMonthlyUsageState value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PlanChangedOperation)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderMonthlyUsageState)); } } } -/// Whether the file was newly created or updated. +/// Units explicitly reported by a quota provider. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct WorkspaceFileChangedOperation : IEquatable +public readonly struct ProviderQuotaUnit : 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 WorkspaceFileChangedOperation(string value) + public ProviderQuotaUnit(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; - /// The workspace file was created. - public static WorkspaceFileChangedOperation Create { get; } = new("create"); + /// AI credits, not tokens or currency. + public static ProviderQuotaUnit AiCredits { get; } = new("ai_credits"); - /// The workspace file was updated. - public static WorkspaceFileChangedOperation Update { get; } = new("update"); + /// Requests charged against an entitlement. + public static ProviderQuotaUnit Requests { get; } = new("requests"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(WorkspaceFileChangedOperation left, WorkspaceFileChangedOperation right) => left.Equals(right); + /// Model tokens. + public static ProviderQuotaUnit Tokens { get; } = new("tokens"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(WorkspaceFileChangedOperation left, WorkspaceFileChangedOperation right) => !(left == right); + /// The observation does not establish a quantity unit. + public static ProviderQuotaUnit Unknown { get; } = new("unknown"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaUnit left, ProviderQuotaUnit right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaUnit left, ProviderQuotaUnit right) => !(left == right); /// - public override bool Equals(object? obj) => obj is WorkspaceFileChangedOperation other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderQuotaUnit other && Equals(other); /// - public bool Equals(WorkspaceFileChangedOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderQuotaUnit other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14709,60 +16241,60 @@ public WorkspaceFileChangedOperation(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 WorkspaceFileChangedOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderQuotaUnit Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, WorkspaceFileChangedOperation value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderQuotaUnit value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(WorkspaceFileChangedOperation)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaUnit)); } } } -/// Origin type of the session being handed off. +/// Timing and purpose of a provider quota observation. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct HandoffSourceType : IEquatable +public readonly struct ProviderQuotaObservationKind : 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 HandoffSourceType(string value) + public ProviderQuotaObservationKind(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; - /// The handoff originated from a remote session. - public static HandoffSourceType Remote { get; } = new("remote"); + /// An explicit account read; consumption may still be subject to service aggregation delay. + public static ProviderQuotaObservationKind AccountSnapshot { get; } = new("account_snapshot"); - /// The handoff originated from a local session. - public static HandoffSourceType Local { get; } = new("local"); + /// A verdict attached before an inference response. May be cached; never a post-charge balance. + public static ProviderQuotaObservationKind AdmissionState { get; } = new("admission_state"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(HandoffSourceType left, HandoffSourceType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaObservationKind left, ProviderQuotaObservationKind right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(HandoffSourceType left, HandoffSourceType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaObservationKind left, ProviderQuotaObservationKind right) => !(left == right); /// - public override bool Equals(object? obj) => obj is HandoffSourceType other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderQuotaObservationKind other && Equals(other); /// - public bool Equals(HandoffSourceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderQuotaObservationKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14770,60 +16302,63 @@ public HandoffSourceType(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 HandoffSourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderQuotaObservationKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, HandoffSourceType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderQuotaObservationKind value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HandoffSourceType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaObservationKind)); } } } -/// Whether the session ended normally ("routine") or due to a crash/fatal error ("error"). +/// Interpretation permitted for independently reported quantities. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ShutdownType : IEquatable +public readonly struct ProviderQuotaQuantityKind : 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 ShutdownType(string value) + public ProviderQuotaQuantityKind(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; - /// The session ended normally. - public static ShutdownType Routine { get; } = new("routine"); + /// Quantities form an authoritative available-of-entitled budget suitable for percentage presentation. + public static ProviderQuotaQuantityKind AuthoritativeBudget { get; } = new("authoritative_budget"); - /// The session ended because of a crash or fatal error. - public static ShutdownType Error { get; } = new("error"); + /// Raw advisory quantities; do not infer permission, usage percentage, reset cadence, or post-charge balance. + public static ProviderQuotaQuantityKind AdvisoryBalance { get; } = new("advisory_balance"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ShutdownType left, ShutdownType right) => left.Equals(right); + /// No quantity measurement, as with admission-only response headers. + public static ProviderQuotaQuantityKind None { get; } = new("none"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ShutdownType left, ShutdownType right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaQuantityKind left, ProviderQuotaQuantityKind right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaQuantityKind left, ProviderQuotaQuantityKind right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ShutdownType other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderQuotaQuantityKind other && Equals(other); /// - public bool Equals(ShutdownType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderQuotaQuantityKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -14831,20 +16366,20 @@ public ShutdownType(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 ShutdownType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderQuotaQuantityKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ShutdownType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderQuotaQuantityKind value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ShutdownType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaQuantityKind)); } } } @@ -16811,6 +18346,70 @@ public override void Write(Utf8JsonWriter writer, AssistantUsageApiEndpoint valu } } +/// Content-Encoding applied to the request body sent on the wire. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ModelCallRequestBodyEncoding : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ModelCallRequestBodyEncoding(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The request body was sent uncompressed (including every WebSocket request). + public static ModelCallRequestBodyEncoding Identity { get; } = new("identity"); + + /// The request body was sent gzip-compressed. + public static ModelCallRequestBodyEncoding Gzip { get; } = new("gzip"); + + /// The request body was sent zstd-compressed. + public static ModelCallRequestBodyEncoding Zstd { get; } = new("zstd"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelCallRequestBodyEncoding left, ModelCallRequestBodyEncoding right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelCallRequestBodyEncoding left, ModelCallRequestBodyEncoding right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ModelCallRequestBodyEncoding other && Equals(other); + + /// + public bool Equals(ModelCallRequestBodyEncoding 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 ModelCallRequestBodyEncoding Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ModelCallRequestBodyEncoding value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelCallRequestBodyEncoding)); + } + } +} + /// Transport used for a successful model call. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] @@ -16872,6 +18471,167 @@ public override void Write(Utf8JsonWriter writer, AssistantUsageTransport value, } } +/// Normalized cause of the WebSocket failure that triggered the HTTP fallback. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ModelCallWebSocketFallbackErrorKind : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ModelCallWebSocketFallbackErrorKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// DNS resolution of the WebSocket host failed. + public static ModelCallWebSocketFallbackErrorKind Dns { get; } = new("dns"); + + /// The TLS handshake or a TLS record failed. + public static ModelCallWebSocketFallbackErrorKind Tls { get; } = new("tls"); + + /// A WebSocket connect or read timed out. + public static ModelCallWebSocketFallbackErrorKind Timeout { get; } = new("timeout"); + + /// The peer refused the TCP connection. + public static ModelCallWebSocketFallbackErrorKind ConnectionRefused { get; } = new("connection_refused"); + + /// The connection was reset, aborted, or ended mid-stream without a close. + public static ModelCallWebSocketFallbackErrorKind ConnectionReset { get; } = new("connection_reset"); + + /// The peer closed the WebSocket. + public static ModelCallWebSocketFallbackErrorKind ClosedByPeer { get; } = new("closed_by_peer"); + + /// The runtime closed the WebSocket itself. + public static ModelCallWebSocketFallbackErrorKind ClosedLocally { get; } = new("closed_locally"); + + /// The socket was already closed before it was used. + public static ModelCallWebSocketFallbackErrorKind NotConnected { get; } = new("not_connected"); + + /// The upgrade or request was rejected with an HTTP status. + public static ModelCallWebSocketFallbackErrorKind HttpStatus { get; } = new("http_status"); + + /// A WebSocket protocol violation or an undecodable frame. + public static ModelCallWebSocketFallbackErrorKind Protocol { get; } = new("protocol"); + + /// The WebSocket request could not be built. + public static ModelCallWebSocketFallbackErrorKind Configuration { get; } = new("configuration"); + + /// A failure that maps onto none of the other kinds. + public static ModelCallWebSocketFallbackErrorKind Other { get; } = new("other"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelCallWebSocketFallbackErrorKind left, ModelCallWebSocketFallbackErrorKind right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelCallWebSocketFallbackErrorKind left, ModelCallWebSocketFallbackErrorKind right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ModelCallWebSocketFallbackErrorKind other && Equals(other); + + /// + public bool Equals(ModelCallWebSocketFallbackErrorKind 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 ModelCallWebSocketFallbackErrorKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ModelCallWebSocketFallbackErrorKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelCallWebSocketFallbackErrorKind)); + } + } +} + +/// Why a WebSocket-capable model call was carried by the HTTP fallback. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ModelCallWebSocketFallbackReason : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ModelCallWebSocketFallbackReason(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The WebSocket connection could not be established. + public static ModelCallWebSocketFallbackReason ConnectFailed { get; } = new("connect_failed"); + + /// No usable WebSocket connection was available for the request. + public static ModelCallWebSocketFallbackReason ConnectionUnavailable { get; } = new("connection_unavailable"); + + /// Sending the request over the WebSocket failed. + public static ModelCallWebSocketFallbackReason SendFailed { get; } = new("send_failed"); + + /// The WebSocket returned a retryable API error. + public static ModelCallWebSocketFallbackReason ApiError { get; } = new("api_error"); + + /// The WebSocket transport failed before any output reached the consumer. + public static ModelCallWebSocketFallbackReason TransportFailed { get; } = new("transport_failed"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelCallWebSocketFallbackReason left, ModelCallWebSocketFallbackReason right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelCallWebSocketFallbackReason left, ModelCallWebSocketFallbackReason right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ModelCallWebSocketFallbackReason other && Equals(other); + + /// + public bool Equals(ModelCallWebSocketFallbackReason 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 ModelCallWebSocketFallbackReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ModelCallWebSocketFallbackReason value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelCallWebSocketFallbackReason)); + } + } +} + /// For HTTP 400 failures only: whether the response carried a structured CAPI error envelope (structured_error, a deterministic validation failure) or no error body (bodyless, the transient gateway/proxy signature). Absent for non-400 failures. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] @@ -17271,7 +19031,7 @@ public override void Write(Utf8JsonWriter writer, AbortReason value, JsonSeriali } } -/// Configuration source: user, workspace, plugin, builtin, or managed. +/// Configuration source: user, workspace, plugin, builtin, managed, or account. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] public readonly struct McpServerSource : IEquatable @@ -17305,6 +19065,9 @@ public McpServerSource(string value) /// Server supplied by a trusted host-managed catalog. public static McpServerSource Managed { get; } = new("managed"); + /// Server contributed by a signed-in account; enablement and organization policy still apply. + public static McpServerSource Account { get; } = new("account"); + /// Returns a value indicating whether two instances are equivalent. public static bool operator ==(McpServerSource left, McpServerSource right) => left.Equals(right); @@ -19634,6 +21397,9 @@ public PermissionApprovalEvaluationReasonCode(string value) /// The script path was not authorized for inspection. public static PermissionApprovalEvaluationReasonCode PathNotAuthorized { get; } = new("path-not-authorized"); + /// A code source was excluded from review by content exclusion policy. + public static PermissionApprovalEvaluationReasonCode ContentExcluded { get; } = new("content-excluded"); + /// The script working directory was invalid. public static PermissionApprovalEvaluationReasonCode InvalidWorkingDirectory { get; } = new("invalid-working-directory"); @@ -19670,6 +21436,24 @@ public PermissionApprovalEvaluationReasonCode(string value) /// The script argument binding could not be reviewed. public static PermissionApprovalEvaluationReasonCode ArgumentBindingUnreviewable { get; } = new("argument-binding-unreviewable"); + /// The shell command could not be analyzed for execution evidence. + public static PermissionApprovalEvaluationReasonCode UnsupportedCommandShape { get; } = new("unsupported-command-shape"); + + /// The shell command used a code source that cannot be bound for review. + public static PermissionApprovalEvaluationReasonCode UnsupportedSource { get; } = new("unsupported-source"); + + /// The shell command used a code source computed at run time. + public static PermissionApprovalEvaluationReasonCode DynamicSource { get; } = new("dynamic-source"); + + /// The shell command referenced more code sources than can be reviewed. + public static PermissionApprovalEvaluationReasonCode TooManySources { get; } = new("too-many-sources"); + + /// A code-bearing executable could not be inspected. + public static PermissionApprovalEvaluationReasonCode ExecutableUnavailable { get; } = new("executable-unavailable"); + + /// A code-bearing executable exceeded the binding size limit. + public static PermissionApprovalEvaluationReasonCode ExecutableTooLarge { get; } = new("executable-too-large"); + /// The script review metadata was malformed. public static PermissionApprovalEvaluationReasonCode MalformedScriptActionReview { get; } = new("malformed-script-action-review"); @@ -20892,6 +22676,74 @@ public override void Write(Utf8JsonWriter writer, AutoModeResolvedReasoningBucke } } +/// Current phase of organization-required plugin preparation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedPluginProgressPhase : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedPluginProgressPhase(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Managed settings are still resolving before plugin preparation can be planned. + public static ManagedPluginProgressPhase Initializing { get; } = new("initializing"); + + /// Required plugin content is being installed. + public static ManagedPluginProgressPhase Installing { get; } = new("installing"); + + /// Installed required plugin content is being updated. + public static ManagedPluginProgressPhase Updating { get; } = new("updating"); + + /// Managed plugin preparation has completed. + public static ManagedPluginProgressPhase Complete { get; } = new("complete"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedPluginProgressPhase left, ManagedPluginProgressPhase right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedPluginProgressPhase left, ManagedPluginProgressPhase right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedPluginProgressPhase other && Equals(other); + + /// + public bool Equals(ManagedPluginProgressPhase 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 ManagedPluginProgressPhase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedPluginProgressPhase value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedPluginProgressPhase)); + } + } +} + /// Summary of which managed-settings channels contributed to the effective session policy. Use the per-channel booleans for exact provenance. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] @@ -20984,7 +22836,7 @@ public ManagedSettingsEnforcedAction(string value) /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// An attempt to turn on a bypass-permissions ("yolo") escalation was refused or capped because policy disables bypass-permissions mode. + /// An attempt to enter a permission mode governed by managed policy was refused or capped. The `setting` and `escalation` fields identify whether this was bypass permissions or Assisted Permissions. public static ManagedSettingsEnforcedAction BypassPermissionsBlocked { get; } = new("bypass_permissions_blocked"); /// Returns a value indicating whether two instances are equivalent. @@ -21023,7 +22875,7 @@ public override void Write(Utf8JsonWriter writer, ManagedSettingsEnforcedAction } } -/// For a `bypass_permissions_blocked` action, which permission-escalation primitive was refused. +/// For a `bypass_permissions_blocked` action, which permission-mode or escalation primitive was refused. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] public readonly struct ManagedSettingsEnforcedEscalation : IEquatable @@ -21048,7 +22900,7 @@ public ManagedSettingsEnforcedEscalation(string value) /// Automatic approval of all tool permission requests. public static ManagedSettingsEnforcedEscalation ApproveAll { get; } = new("approve_all"); - /// Assisted mode — keeps normal prompt paths and adds an LLM recommendation, distinct from allow-all. + /// Assisted Permissions — uses an LLM review to reduce prompts, distinct from allow-all and not a hard security boundary. public static ManagedSettingsEnforcedEscalation AssistedApproval { get; } = new("assisted_approval"); /// Unrestricted filesystem access outside the session's allowed directories. @@ -21471,7 +23323,7 @@ public McpServerStatus(string value) /// The server is configured but disabled. public static McpServerStatus Disabled { get; } = new("disabled"); - /// The server was intentionally stopped and can be restarted on demand when policy permits; a server quarantined by restrictive managed policy stays stopped and cannot be restarted until the policy allows it. + /// The server is not running: it may not have started yet, may have been explicitly stopped, or may be quarantined by restrictive managed policy. It can be restarted on demand when policy permits. public static McpServerStatus Stopped { get; } = new("stopped"); /// The server is not configured for this session. @@ -21795,6 +23647,7 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(HumanResponseRecordedResponseAskUser))] [JsonSerializable(typeof(HumanResponseRecordedResponseExitPlanMode))] [JsonSerializable(typeof(HumanResponseRecordedResponseUserInput))] +[JsonSerializable(typeof(ManagedPermissionsContext))] [JsonSerializable(typeof(McpAppToolCallCompleteData))] [JsonSerializable(typeof(McpAppToolCallCompleteError))] [JsonSerializable(typeof(McpAppToolCallCompleteEvent))] @@ -21828,6 +23681,7 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(ModelCallFinishedEvent))] [JsonSerializable(typeof(ModelCallStartData))] [JsonSerializable(typeof(ModelCallStartEvent))] +[JsonSerializable(typeof(ModelProviderRef))] [JsonSerializable(typeof(OmittedBinaryResult))] [JsonSerializable(typeof(PendingMessagesModifiedData))] [JsonSerializable(typeof(PendingMessagesModifiedEvent))] @@ -21894,10 +23748,15 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(PermissionResultDeniedNoApprovalRuleAndCouldNotRequestFromUser))] [JsonSerializable(typeof(PermissionRule))] [JsonSerializable(typeof(PermissionSandboxPathGrant))] +[JsonSerializable(typeof(PermissionWriteFileContent))] +[JsonSerializable(typeof(PermissionWriteFileEdit))] [JsonSerializable(typeof(PersistedBinaryImage))] [JsonSerializable(typeof(PersistedBinaryResult))] [JsonSerializable(typeof(PromptCacheBreakData))] [JsonSerializable(typeof(PromptCacheBreakEvent))] +[JsonSerializable(typeof(ProviderMonthlyUsage))] +[JsonSerializable(typeof(ProviderQuotaBudgetMetadata))] +[JsonSerializable(typeof(ProviderQuotaState))] [JsonSerializable(typeof(ResponsesReasoning))] [JsonSerializable(typeof(SamplingCompletedData))] [JsonSerializable(typeof(SamplingCompletedEvent))] @@ -21986,6 +23845,8 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(SessionLimitsExhaustedRequestedData))] [JsonSerializable(typeof(SessionLimitsExhaustedRequestedEvent))] [JsonSerializable(typeof(SessionLimitsExhaustedResponse))] +[JsonSerializable(typeof(SessionManagedPluginProgressData))] +[JsonSerializable(typeof(SessionManagedPluginProgressEvent))] [JsonSerializable(typeof(SessionManagedSettingsEnforcedData))] [JsonSerializable(typeof(SessionManagedSettingsEnforcedEvent))] [JsonSerializable(typeof(SessionManagedSettingsResolvedData))] @@ -22012,6 +23873,8 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(SessionPermissionsChangedEvent))] [JsonSerializable(typeof(SessionPlanChangedData))] [JsonSerializable(typeof(SessionPlanChangedEvent))] +[JsonSerializable(typeof(SessionQuotaObservationData))] +[JsonSerializable(typeof(SessionQuotaObservationEvent))] [JsonSerializable(typeof(SessionRemoteSteerableChangedData))] [JsonSerializable(typeof(SessionRemoteSteerableChangedEvent))] [JsonSerializable(typeof(SessionResumeData))] @@ -22143,7 +24006,17 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(ToolUserRequestedEvent))] [JsonSerializable(typeof(UiEphemeralQueryData))] [JsonSerializable(typeof(UiEphemeralQueryEvent))] +[JsonSerializable(typeof(UsageAccountingIdentity))] [JsonSerializable(typeof(UsageCheckpointModelCacheState))] +[JsonSerializable(typeof(UsageGetMetricsResult))] +[JsonSerializable(typeof(UsageMetricsAgentMetric))] +[JsonSerializable(typeof(UsageMetricsCodeChanges))] +[JsonSerializable(typeof(UsageMetricsModelMetric))] +[JsonSerializable(typeof(UsageMetricsModelMetricRequests))] +[JsonSerializable(typeof(UsageMetricsModelMetricTokenDetail))] +[JsonSerializable(typeof(UsageMetricsModelMetricUsage))] +[JsonSerializable(typeof(UsageMetricsProviderModelMetric))] +[JsonSerializable(typeof(UsageMetricsTokenDetail))] [JsonSerializable(typeof(UserInputCompletedData))] [JsonSerializable(typeof(UserInputCompletedEvent))] [JsonSerializable(typeof(UserInputRequestedData))] diff --git a/dotnet/src/Host.cs b/dotnet/src/Host.cs index 5835ea3a4c..9ce98c3212 100644 --- a/dotnet/src/Host.cs +++ b/dotnet/src/Host.cs @@ -39,6 +39,8 @@ public sealed record AhpSessionResumeRequest(string SessionId, ResumeSessionConf [Experimental(Diagnostics.Experimental)] public sealed class AhpHostOptions { + /// Stable durable catalog identity; must agree with GitHubEnvironment.ComputeId when both are supplied. + public string? ComputeId { get; init; } /// Local WebSocket transport settings; absent disables the local listener. public HostLocalServerOptions? LocalServer { get; init; } /// GitHub Mission Control transport settings, with required Name and ComputeId; absent disables it. @@ -84,10 +86,14 @@ internal AhpHost(HostStartResult info, ServerHostApi rpc) /// The GitHub Mission Control environment ID, absent without a GitHub environment. public string? EnvironmentId { get; } - /// Publishes a resident session without invoking factories or transferring ownership. + /// Durably advertises an attached session without invoking factories or transferring ownership. public Task PublishSessionAsync(string sessionId, CancellationToken cancellationToken = default) => _rpc.PublishSessionAsync(HostId, sessionId, cancellationToken); + /// Lists all live and dormant catalog sessions advertised by this host. + public Task ListSessionsAsync(CancellationToken cancellationToken = default) + => _rpc.ListSessionsAsync(HostId, cancellationToken); + /// Stops and joins listener cleanup without deleting application sessions. public ValueTask DisposeAsync() => new(DisposeAsync(CancellationToken.None)); @@ -121,7 +127,8 @@ public async Task StartAhpHostAsync(AhpHostOptions options, Cancellatio var githubEnvironment = options.GitHubEnvironment is { } github ? new HostGitHubEnvironmentOptions { Name = github.Name, - ComputeId = github.ComputeId + ComputeId = github.ComputeId, + RequireConnectionBinding = github.RequireConnectionBinding } : null; if (localServer is null && githubEnvironment is null) throw new ArgumentException("At least one AHP transport must be configured", nameof(options)); @@ -130,9 +137,15 @@ public async Task StartAhpHostAsync(AhpHostOptions options, Cancellatio var hostId = Guid.NewGuid().ToString(); lock (_ahpGate) _ahpHosts.Add(hostId, options); var rpc = connection.Server.Host; - var startup = rpc.StartAsync(hostId, localServer, githubEnvironment, - options.CreateSession is not null ? true : null, - options.ResumeSession is not null ? true : null, CancellationToken.None); + var startup = rpc.StartAsync(new HostStartRequest + { + HostId = hostId, + ComputeId = options.ComputeId, + LocalServer = localServer, + GitHubEnvironment = githubEnvironment, + SessionFactory = options.CreateSession is not null ? true : null, + ResumeFactory = options.ResumeSession is not null ? true : null + }, CancellationToken.None); try { var info = await startup.WaitAsync(Timeout.InfiniteTimeSpan, cancellationToken).ConfigureAwait(false); diff --git a/dotnet/src/JsonRpc.cs b/dotnet/src/JsonRpc.cs index 26d4fe297a..8d45eb6f4a 100644 --- a/dotnet/src/JsonRpc.cs +++ b/dotnet/src/JsonRpc.cs @@ -1039,11 +1039,12 @@ private sealed class IncomingRequestCancellation : IDisposable public IncomingRequestCancellation(long id, CancellationToken connectionClosedToken) { Id = id; - _combinedSource = CancellationTokenSource.CreateLinkedTokenSource(_requestSource.Token, connectionClosedToken); _registration = _requestSource.Token.Register(static state => { ((TaskCompletionSource)state!).TrySetResult(); }, _requestCancelled); + // Cancellation callbacks run in reverse registration order: propagate to handlers before replying. + _combinedSource = CancellationTokenSource.CreateLinkedTokenSource(_requestSource.Token, connectionClosedToken); } public long Id { get; } diff --git a/dotnet/src/Session.StructuredOutput.cs b/dotnet/src/Session.StructuredOutput.cs index 6df54d121e..c190c13ee3 100644 --- a/dotnet/src/Session.StructuredOutput.cs +++ b/dotnet/src/Session.StructuredOutput.cs @@ -192,10 +192,10 @@ void ProcessEvent(SessionEvent evt) } pendingEvents.Clear(); } - await Task.WhenAny(completion.Task, JsonRpc.Completion, _eventChannel.Reader.Completion); + await Task.WhenAny(completion.Task, _eventDispatchStopped.Task, JsonRpc.Completion, _eventChannel.Reader.Completion); if (!completion.Task.IsCompleted) { - throw new IOException("The session closed before a final structured response was received."); + completion.TrySetException(new IOException("The session closed before a final structured response was received.")); } return await completion.Task; } diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs index f0cdde8999..79afecd20b 100644 --- a/dotnet/src/Session.cs +++ b/dotnet/src/Session.cs @@ -59,8 +59,10 @@ namespace GitHub.Copilot; public sealed partial class CopilotSession : IAsyncDisposable { private IReadOnlyDictionary _toolHandlers = new Dictionary(StringComparer.Ordinal); - private readonly Dictionary> _commandHandlers = []; - private readonly Dictionary>> _bearerTokenProviders = new(StringComparer.Ordinal); + private Dictionary> _commandHandlers = new(StringComparer.Ordinal); + private IReadOnlyDictionary>> _bearerTokenProviders = new Dictionary>>(StringComparer.Ordinal); + private readonly object _callbackLock = new(); + private bool _callbacksRetired; private readonly ConcurrentDictionary _pendingExternalTools = new(StringComparer.Ordinal); private readonly CancellationTokenSource _externalToolLifetime = new(); private readonly ILogger _logger; @@ -73,16 +75,29 @@ public sealed partial class CopilotSession : IAsyncDisposable private volatile Func>? _elicitationHandler; private volatile Func>? _exitPlanModeHandler; private volatile Func>? _autoModeSwitchHandler; + private volatile ISkillProvider? _skillProvider; private ImmutableArray _eventHandlers = ImmutableArray.Empty; - private sealed record EventSubscription(Type EventType, Action Handler, bool RootAgentOnly); + private sealed class EventSubscription(Type eventType, Action handler, bool rootAgentOnly) + { + private Action? _handler = handler; + + public Type EventType { get; } = eventType; + public bool RootAgentOnly { get; } = rootAgentOnly; + + // Keep the user handler out of the retained unsubscribe callback's closure. + public static EventSubscription Create(Action handler, bool rootAgentOnly) where T : SessionEvent => + new(typeof(T), evt => handler((T)evt), rootAgentOnly); + + public void Invoke(SessionEvent sessionEvent) => Volatile.Read(ref _handler)?.Invoke(sessionEvent); + + public void ClearHandler() => Interlocked.Exchange(ref _handler, null); + } private SessionHooks? _hooks; - private readonly SemaphoreSlim _hooksLock = new(1, 1); private readonly SemaphoreSlim _setToolsLock = new(1, 1); private Dictionary>>? _transformCallbacks; - private readonly SemaphoreSlim _transformCallbacksLock = new(1, 1); private IReadOnlyList _openCanvases = Array.Empty(); @@ -93,9 +108,10 @@ private sealed record EventSubscription(Type EventType, Action Han /// Channel that serializes event dispatch. enqueues; /// a single background consumer () dequeues and /// invokes handlers one at a time, preserving arrival order. + /// Shutdown can drain concurrently without waiting for an in-flight handler. /// - private readonly Channel _eventChannel = Channel.CreateUnbounded( - new() { SingleReader = true }); + private readonly Channel _eventChannel = Channel.CreateUnbounded(); + private readonly TaskCompletionSource _eventDispatchStopped = new(TaskCreationOptions.RunContinuationsAsynchronously); /// /// Fixed name of the runtime's built-in tool-search tool. A client can @@ -213,19 +229,56 @@ internal void RemoveFromClient() } /// - /// Stops the session's event consumer () without - /// making an RPC. and - /// use this on error paths where a - /// locally registered session fails before it can be returned to the caller: - /// starts the consumer eagerly, and no caller - /// ever receives the failed session to dispose it. Safe to call more than once — - /// is idempotent. + /// Retires the event consumer without making an RPC or joining an admitted handler. + /// Releases queued events and subscriptions and fails pending response waiters. + /// Also used for registered sessions that fail before being returned to the caller. + /// Safe to call more than once. /// internal void CloseEventChannel() { + _eventDispatchStopped.TrySetResult(true); _eventChannel.Writer.TryComplete(); + while (_eventChannel.Reader.TryRead(out _)) + { + // Discard queued events; retirement must not dispatch their handlers. + } + var subscriptions = ImmutableInterlocked.InterlockedExchange(ref _eventHandlers, ImmutableArray.Empty); + foreach (var subscription in subscriptions) + { + subscription.ClearHandler(); + } + } + + /// Releases local callback ownership without an RPC or joining admitted handlers. + internal void Retire() + { + lock (_callbackLock) + { + _callbacksRetired = true; + Volatile.Write(ref _toolHandlers, new Dictionary(StringComparer.Ordinal)); + _commandHandlers = new Dictionary>(StringComparer.Ordinal); + _bearerTokenProviders = new Dictionary>>(StringComparer.Ordinal); + _permissionHandler = null; + _mcpAuthHandler = null; + _userInputHandler = null; + _elicitationHandler = null; + _exitPlanModeHandler = null; + _autoModeSwitchHandler = null; + _skillProvider = null; + _hooks = null; + _transformCallbacks = null; + ClientSessionApis.ProviderToken = null; + ClientSessionApis.Canvas = null; + ClientSessionApis.SessionFs = null; + } + CancelPendingExternalTools(); + CloseEventChannel(); + ReleaseGitHubTokenProviderRegistration(); } + private void ThrowIfCallbacksRetired() => + ObjectDisposedException.ThrowIf(_callbacksRetired, this); + /// /// Removes the session from its parent client and stops its event consumer. /// Used on session-creation/resume error paths where the session was registered @@ -233,8 +286,7 @@ internal void CloseEventChannel() /// internal void Unregister() { - CancelPendingExternalTools(); - CloseEventChannel(); + Retire(); RemoveFromClient(); } @@ -369,6 +421,7 @@ public async Task SendAsync(MessageOptions options, CancellationToken ca /// Thrown if the timeout is reached before the session becomes idle. /// Thrown if the is cancelled. /// Thrown if the session has been disposed. + /// Thrown if session event delivery stops before a final response arrives. /// /// /// This is a convenience method that combines with waiting for @@ -454,6 +507,11 @@ void Handler(SessionEvent evt) }); try { + await Task.WhenAny(tcs.Task, _eventDispatchStopped.Task); + if (!tcs.Task.IsCompleted) + { + tcs.TrySetException(new IOException("The session closed before a final response was received.")); + } var result = await tcs.Task; LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null, "CopilotSession.SendAndWaitAsync complete. Elapsed={Elapsed}, SessionId={SessionId}, CompletedBy={CompletedBy}, AssistantMessageReceived={AssistantMessageReceived}", @@ -488,6 +546,8 @@ void Handler(SessionEvent evt) /// /// A callback to be invoked when a session event occurs. /// An that, when disposed, unsubscribes the handler. + /// Thrown if the session has been disposed. + /// Thrown if session event delivery has stopped. /// /// /// Events include assistant messages, tool executions, errors, and session state changes. @@ -498,6 +558,10 @@ void Handler(SessionEvent evt) /// A handler will never be called concurrently with itself or with other handlers /// on the same session. /// + /// + /// Unsubscribing or closing the session releases handlers that have not been admitted + /// for dispatch. A handler already admitted may finish; disposal does not wait for it. + /// /// /// /// @@ -529,9 +593,20 @@ private ActionDisposable OnCore(Action handler, bool rootAgentOnly) where ArgumentNullException.ThrowIfNull(handler); ThrowIfDisposed(); - var subscription = new EventSubscription(typeof(T), evt => handler((T)evt), rootAgentOnly); + var subscription = EventSubscription.Create(handler, rootAgentOnly); ImmutableInterlocked.Update(ref _eventHandlers, array => array.Add(subscription)); - return new ActionDisposable(() => ImmutableInterlocked.Update(ref _eventHandlers, array => array.Remove(subscription))); + if (_eventDispatchStopped.Task.IsCompleted) + { + subscription.ClearHandler(); + ImmutableInterlocked.Update(ref _eventHandlers, array => array.Remove(subscription)); + ThrowIfDisposed(); + throw new IOException("The session event dispatch has stopped."); + } + return new ActionDisposable(() => + { + subscription.ClearHandler(); + ImmutableInterlocked.Update(ref _eventHandlers, array => array.Remove(subscription)); + }); } /// @@ -567,12 +642,20 @@ private async Task ProcessEventsAsync() { await foreach (var sessionEvent in _eventChannel.Reader.ReadAllAsync()) { + if (_eventDispatchStopped.Task.IsCompleted) + { + return; + } var dispatchTimestamp = Stopwatch.GetTimestamp(); var eventType = sessionEvent.GetType(); // Preserve wire attribution without moving waiters ahead of earlier user handlers. var isRootAgentEvent = string.IsNullOrEmpty(sessionEvent.AgentId); foreach (var subscription in _eventHandlers) { + if (_eventDispatchStopped.Task.IsCompleted) + { + return; + } if (!subscription.EventType.IsAssignableFrom(eventType) || (subscription.RootAgentOnly && !isRootAgentEvent)) { @@ -580,7 +663,7 @@ private async Task ProcessEventsAsync() } try { - subscription.Handler(sessionEvent); + subscription.Invoke(sessionEvent); } catch (Exception ex) { @@ -606,7 +689,16 @@ private async Task ProcessEventsAsync() /// internal void RegisterTools(ICollection tools) { - Volatile.Write(ref _toolHandlers, BuildToolHandlerMap(tools)); + SetToolHandlers(BuildToolHandlerMap(tools)); + } + + private void SetToolHandlers(Dictionary handlers) + { + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + Volatile.Write(ref _toolHandlers, handlers); + } } private static Dictionary BuildToolHandlerMap(ICollection tools) @@ -693,9 +785,10 @@ private static Dictionary ToJsonElementDictionary(IDictiona /// are the same as the tools supplied when creating or resuming a session. /// /// - /// Tool handlers switch after the runtime accepts the replacement. Tool calls already running finish with the handlers - /// that started them. If the runtime rejects the replacement, the previous handlers remain installed and the exception is - /// propagated. Concurrent calls are applied in order. + /// Tool handlers switch when the runtime's acceptance response arrives, before subsequent tool requests are dispatched. + /// Tool calls already running finish with the handlers that started them. If the runtime rejects the replacement, the + /// previous handlers remain installed and the exception is propagated. Concurrent calls are applied in order. + /// Acceptance after local retirement fails the replacement without restoring its handlers. /// /// /// The agent sees the new tools from its next model request, which can fall within a turn in progress. A model request @@ -714,9 +807,8 @@ public async Task SetToolsAsync(ICollection tools, Cancel var wireTools = tools.Select(ToProtocolExternalToolDefinition).ToList(); var handlers = BuildToolHandlerMap(tools); - // Cancelling while an earlier call holds the lock sends nothing. Once this call holds it, the - // request runs to completion even if the caller stops waiting, so an accepted replacement still - // installs its handlers. + // Cancelling before sending the request leaves handlers unchanged. Once sent, the request runs + // to completion even if the caller stops waiting, so an accepted replacement still installs its handlers. var replacement = ReplaceToolsAsync(wireTools, handlers, cancellationToken); try { @@ -741,8 +833,13 @@ private async Task ReplaceToolsAsync( await _setToolsLock.WaitAsync(lockCancellationToken); try { - await Rpc.Tools.SetAsync(wireTools, CancellationToken.None); - Volatile.Write(ref _toolHandlers, handlers); + // SemaphoreSlim can grant a released slot while its cancellation continuation is pending. + lockCancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + var request = new ToolsSetRequest { SessionId = SessionId, Tools = wireTools }; + await CopilotClient.InvokeRpcAsync( + JsonRpc, "session.tools.set", [request], null, CancellationToken.None, + onResponseInline: _ => SetToolHandlers(handlers)); } finally { @@ -757,8 +854,12 @@ private async Task ReplaceToolsAsync( /// The tool if found; otherwise, null. internal AIFunction? GetTool(string name) { - var handlers = Volatile.Read(ref _toolHandlers); - return handlers.TryGetValue(name, out var tool) ? tool : null; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + var handlers = Volatile.Read(ref _toolHandlers); + return handlers.TryGetValue(name, out var tool) ? tool : null; + } } /// @@ -774,13 +875,21 @@ internal void RegisterPermissionHandler( Func>? handler, bool managedSettingsEnabled) { - _permissionHandler = handler; - _managedSettingsEnabled = managedSettingsEnabled; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _permissionHandler = handler; + _managedSettingsEnabled = managedSettingsEnabled; + } } internal void RegisterMcpAuthHandler(Func>? handler) { - _mcpAuthHandler = handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _mcpAuthHandler = handler; + } } /// @@ -790,7 +899,12 @@ internal void RegisterMcpAuthHandler(Func>? /// A task that resolves with the permission decision. internal async Task HandlePermissionRequestAsync(JsonElement permissionRequestData) { - var handler = _permissionHandler; + Func>? handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + handler = _permissionHandler; + } if (handler == null) { @@ -838,7 +952,7 @@ private async Task HandleBroadcastEventAsync(SessionEvent sessionEvent) return; // This client doesn't handle this tool; another client will. using (TelemetryHelpers.RestoreTraceContext(data.Traceparent, data.Tracestate)) - await ExecuteToolAndRespondAsync(data.RequestId, data.ToolName, data.ToolCallId, data.Arguments, tool); + await ExecuteToolAndRespondAsync(data.RequestId, data.ToolName, data.ToolCallId, data.Arguments, tool, toolEvent.AgentId); break; } @@ -855,7 +969,12 @@ private async Task HandleBroadcastEventAsync(SessionEvent sessionEvent) if (data.ResolvedByHook == true) return; // Already resolved by a permissionRequest hook; no client action needed. - var handler = _permissionHandler; + Func>? handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + handler = _permissionHandler; + } if (handler is null) return; // This client doesn't handle permissions; another client will. @@ -869,7 +988,12 @@ private async Task HandleBroadcastEventAsync(SessionEvent sessionEvent) if (string.IsNullOrEmpty(data.RequestId)) return; - var handler = _mcpAuthHandler; + Func>? handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + handler = _mcpAuthHandler; + } if (handler is null) { if (_logger.IsEnabled(LogLevel.Warning)) @@ -1053,7 +1177,7 @@ private async Task TryCancelMcpAuthRequestAsync(string requestId) /// /// Executes a tool handler and sends the result back via the HandlePendingToolCall RPC. /// - private async Task ExecuteToolAndRespondAsync(string requestId, string toolName, string toolCallId, JsonElement? arguments, AIFunction tool) + private async Task ExecuteToolAndRespondAsync(string requestId, string toolName, string toolCallId, JsonElement? arguments, AIFunction tool, string? agentId) { if (_externalToolLifetime.IsCancellationRequested) { @@ -1078,7 +1202,9 @@ private async Task ExecuteToolAndRespondAsync(string requestId, string toolName, SessionId = SessionId, ToolCallId = toolCallId, ToolName = toolName, - Arguments = arguments + Arguments = arguments, + AgentId = string.IsNullOrEmpty(agentId) ? null : agentId, + RequestId = requestId }; // The built-in tool-search tool receives a snapshot of the session's @@ -1358,7 +1484,11 @@ private async Task ExecutePermissionAndRespondAsync(string requestId, Permission /// The handler to invoke when user input is requested. internal void RegisterUserInputHandler(Func> handler) { - _userInputHandler = handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _userInputHandler = handler; + } } /// @@ -1367,11 +1497,18 @@ internal void RegisterUserInputHandler(FuncThe command definitions to register. internal void RegisterCommands(IEnumerable? commands) { - _commandHandlers.Clear(); - if (commands is null) return; - foreach (var cmd in commands) + var handlers = new Dictionary>(StringComparer.Ordinal); + if (commands is not null) + { + foreach (var cmd in commands) + { + handlers[cmd.Name] = cmd.Handler; + } + } + lock (_callbackLock) { - _commandHandlers[cmd.Name] = cmd.Handler; + ThrowIfCallbacksRetired(); + _commandHandlers = handlers; } } @@ -1381,7 +1518,11 @@ internal void RegisterCommands(IEnumerable? commands) /// The handler to invoke when an elicitation request is received. internal void RegisterElicitationHandler(Func>? handler) { - _elicitationHandler = handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _elicitationHandler = handler; + } } /// @@ -1390,7 +1531,11 @@ internal void RegisterElicitationHandler(FuncThe handler to invoke when an exit-plan-mode request is received. internal void RegisterExitPlanModeHandler(Func>? handler) { - _exitPlanModeHandler = handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _exitPlanModeHandler = handler; + } } /// @@ -1399,7 +1544,73 @@ internal void RegisterExitPlanModeHandler(FuncThe handler to invoke when an auto-mode-switch request is received. internal void RegisterAutoModeSwitchHandler(Func>? handler) { - _autoModeSwitchHandler = handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _autoModeSwitchHandler = handler; + } + } + + /// + /// Registers the session-scoped skill provider callback. + /// + internal void RegisterSkillProvider(ISkillProvider? provider) + { + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _skillProvider = provider; + } + } + + internal void ClearSkillProvider() + { + lock (_callbackLock) + { + _skillProvider = null; + } + } + + internal async ValueTask HandleSkillProviderListAsync(CancellationToken cancellationToken) + { + ISkillProvider provider; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + provider = _skillProvider ?? throw new InvalidOperationException($"No skill provider for session: {SessionId}"); + } + + try + { + var skills = await provider.ListSkillsAsync(cancellationToken).ConfigureAwait(false); + return new CopilotClient.SkillProviderListResult(skills?.ToList() ?? []); + } + catch (Exception ex) when (ex is not OperationCanceledException || !cancellationToken.IsCancellationRequested) + { + LogSkillProviderFailed(ex, "listSkills", SessionId); + throw new InvalidOperationException("Skill provider listSkills failed", ex); + } + } + + internal async ValueTask HandleSkillProviderReadAsync(string name, CancellationToken cancellationToken) + { + ISkillProvider provider; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + provider = _skillProvider ?? throw new InvalidOperationException($"No skill provider for session: {SessionId}"); + } + + try + { + var markdown = await provider.ReadSkillAsync(name, cancellationToken).ConfigureAwait(false); + return new CopilotClient.SkillProviderReadResult(markdown); + } + catch (Exception ex) when (ex is not OperationCanceledException || !cancellationToken.IsCancellationRequested) + { + LogSkillProviderFailed(ex, "readSkill", SessionId); + throw new InvalidOperationException("Skill provider readSkill failed", ex); + } } /// @@ -1416,17 +1627,20 @@ internal void RegisterAutoModeSwitchHandler(FuncMap of provider name to callback, or null/empty to clear. internal void RegisterBearerTokenProviders(IReadOnlyDictionary>>? providers) { - _bearerTokenProviders.Clear(); - if (providers is null || providers.Count == 0) + var callbacks = new Dictionary>>(StringComparer.Ordinal); + if (providers is not null) { - ClientSessionApis.ProviderToken = null; - return; + foreach (var (name, callback) in providers) + { + callbacks[name] = callback; + } } - foreach (var (name, callback) in providers) + lock (_callbackLock) { - _bearerTokenProviders[name] = callback; + ThrowIfCallbacksRetired(); + _bearerTokenProviders = callbacks; + ClientSessionApis.ProviderToken = callbacks.Count == 0 ? null : new BearerTokenProviderHandler(this); } - ClientSessionApis.ProviderToken = new BearerTokenProviderHandler(this); } /// @@ -1437,10 +1651,15 @@ private sealed class BearerTokenProviderHandler(CopilotSession session) : IProvi { public async Task GetTokenAsync(ProviderTokenAcquireRequest request, CancellationToken cancellationToken = default) { - if (!session._bearerTokenProviders.TryGetValue(request.ProviderName, out var callback)) + Func>? callback; + lock (session._callbackLock) { - throw new InvalidOperationException( - $"No bearer-token provider registered for provider \"{request.ProviderName}\""); + session.ThrowIfCallbacksRetired(); + if (!session._bearerTokenProviders.TryGetValue(request.ProviderName, out callback)) + { + throw new InvalidOperationException( + $"No bearer-token provider registered for provider \"{request.ProviderName}\""); + } } var token = await callback(new ProviderTokenArgs { ProviderName = request.ProviderName, SessionId = request.SessionId }).ConfigureAwait(false); return new ProviderTokenAcquireResult { Token = token }; @@ -1523,7 +1742,20 @@ private void RemoveOpenCanvas(string instanceId) internal void SetCanvasHandler(ICanvasHandler? handler) { - ClientSessionApis.Canvas = handler is null ? null : new CanvasHandlerAdapter(handler); + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + ClientSessionApis.Canvas = handler is null ? null : new CanvasHandlerAdapter(handler); + } + } + + internal void SetSessionFsHandler(Rpc.ISessionFsHandler handler) + { + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + ClientSessionApis.SessionFs = handler; + } } private static readonly JsonElement NullJsonElement = JsonElement.Parse("null"); @@ -1592,7 +1824,13 @@ public async Task InvokeAsync(CanvasProviderInvokeActionRequest request, /// private async Task ExecuteCommandAndRespondAsync(string requestId, string commandName, string command, string args) { - if (!_commandHandlers.TryGetValue(commandName, out var handler)) + Func? handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + _commandHandlers.TryGetValue(commandName, out handler); + } + if (handler is null) { try { @@ -1652,7 +1890,12 @@ await handler(new CommandContext /// private async Task HandleElicitationRequestAsync(ElicitationContext context, string requestId) { - var handler = _elicitationHandler; + Func>? handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + handler = _elicitationHandler; + } if (handler is null) return; try @@ -1852,7 +2095,12 @@ public async Task ConfirmAsync(string message, CancellationToken cancellat /// A task that resolves with the user's response. internal async Task HandleUserInputRequestAsync(UserInputRequest request) { - var handler = _userInputHandler ?? throw new InvalidOperationException("No user input handler registered"); + Func> handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + handler = _userInputHandler ?? throw new InvalidOperationException("No user input handler registered"); + } var invocation = new UserInputInvocation { SessionId = SessionId @@ -1874,7 +2122,12 @@ internal async Task HandleUserInputRequestAsync(UserInputRequ /// A task that resolves with the user's decision. internal async Task HandleExitPlanModeRequestAsync(ExitPlanModeRequest request) { - var handler = _exitPlanModeHandler; + Func>? handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + handler = _exitPlanModeHandler; + } if (handler is null) { return new ExitPlanModeResult { Approved = true }; @@ -1897,7 +2150,12 @@ internal async Task HandleExitPlanModeRequestAsync(ExitPlanM /// A task that resolves with the user's decision. internal async Task HandleAutoModeSwitchRequestAsync(AutoModeSwitchRequest request) { - var handler = _autoModeSwitchHandler; + Func>? handler; + lock (_callbackLock) + { + ThrowIfCallbacksRetired(); + handler = _autoModeSwitchHandler; + } if (handler is null) { return AutoModeSwitchResponse.No; @@ -1919,15 +2177,11 @@ internal async Task HandleAutoModeSwitchRequestAsync(Aut /// The hooks configuration. internal void RegisterHooks(SessionHooks hooks) { - _hooksLock.Wait(); - try + lock (_callbackLock) { + ThrowIfCallbacksRetired(); _hooks = hooks; } - finally - { - _hooksLock.Release(); - } } /// @@ -1938,16 +2192,12 @@ internal void RegisterHooks(SessionHooks hooks) /// A task that resolves with the hook output. internal async Task HandleHooksInvokeAsync(string hookType, JsonElement input) { - await _hooksLock.WaitAsync(); SessionHooks? hooks; - try + lock (_callbackLock) { + ThrowIfCallbacksRetired(); hooks = _hooks; } - finally - { - _hooksLock.Release(); - } if (hooks == null) { @@ -2051,15 +2301,11 @@ internal void RegisterHooks(SessionHooks hooks) /// The transform callbacks keyed by section identifier. internal void RegisterTransformCallbacks(Dictionary>>? callbacks) { - _transformCallbacksLock.Wait(); - try + lock (_callbackLock) { + ThrowIfCallbacksRetired(); _transformCallbacks = callbacks; } - finally - { - _transformCallbacksLock.Release(); - } } /// @@ -2070,15 +2316,11 @@ internal void RegisterTransformCallbacks(Dictionary HandleSystemMessageTransformAsync(JsonElement sections) { Dictionary>>? callbacks; - await _transformCallbacksLock.WaitAsync(); - try + lock (_callbackLock) { + ThrowIfCallbacksRetired(); callbacks = _transformCallbacks; } - finally - { - _transformCallbacksLock.Release(); - } var parsed = JsonSerializer.Deserialize( sections.GetRawText(), @@ -2224,7 +2466,7 @@ public async Task SetModelAsync(string model, SetModelOptions options, Cancellat if (options.ResetAutoTier) { - var request = new ModelSwitchToRequest + var request = new ModelSwitchToRequestWithSession { SessionId = SessionId, ModelId = model, @@ -2236,7 +2478,7 @@ public async Task SetModelAsync(string model, SetModelOptions options, Cancellat await CopilotClient.InvokeRpcAsync( Rpc, "session.model.switchTo", - [WithExplicitNullAutoTier(request, RpcJsonContext.Default.ModelSwitchToRequest)], + [WithExplicitNullAutoTier(request, RpcJsonContext.Default.ModelSwitchToRequestWithSession)], cancellationToken); return; } @@ -2373,6 +2615,11 @@ public async Task LogAsync(string message, SessionLogLevel? level = null, bool? /// /// After calling this method, the session object can no longer be used. /// + /// + /// Stops subscribed event delivery and releases queued events and subscriptions. + /// Handlers already admitted for dispatch may finish; disposal does not wait for them. + /// Pending response waiters fail if the session closes before their final response. + /// /// /// /// @@ -2392,6 +2639,7 @@ public async ValueTask DisposeAsync() return; } + ClearSkillProvider(); CancelPendingExternalTools(); CloseEventChannel(); @@ -2414,20 +2662,10 @@ public async ValueTask DisposeAsync() } finally { - ReleaseGitHubTokenProviderRegistration(); + Retire(); RemoveFromClient(); GC.SuppressFinalize(this); } - - _eventHandlers = ImmutableInterlocked.InterlockedExchange(ref _eventHandlers, ImmutableArray.Empty); - Volatile.Write(ref _toolHandlers, new Dictionary(StringComparer.Ordinal)); - _commandHandlers.Clear(); - - _permissionHandler = null; - _userInputHandler = null; - _elicitationHandler = null; - _exitPlanModeHandler = null; - _autoModeSwitchHandler = null; } [LoggerMessage(Level = LogLevel.Error, Message = "Unhandled exception in broadcast event handler")] @@ -2445,6 +2683,9 @@ public async ValueTask DisposeAsync() [LoggerMessage(Level = LogLevel.Error, Message = "Permission handler or response delivery failed. SessionId={SessionId}, RequestId={RequestId}")] private partial void LogPermissionHandlerOrDeliveryFailed(Exception exception, string sessionId, string requestId); + [LoggerMessage(Level = LogLevel.Warning, Message = "Skill provider {Operation} failed. SessionId={SessionId}")] + private partial void LogSkillProviderFailed(Exception exception, string operation, string sessionId); + internal record SendMessageRequest { public string SessionId { get; init; } = string.Empty; diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index 7ed04c279b..9a70de1fc3 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -52,6 +52,74 @@ internal static class Diagnostics internal const string Experimental = "GHCP001"; } +/// +/// Describes a skill supplied by a session-scoped . +/// +/// +/// Experimental. The runtime validates descriptor limits, name syntax, and +/// case-insensitive uniqueness when it reads the provider catalog. +/// +[Experimental(Diagnostics.Experimental)] +public sealed class SkillProviderDescriptor +{ + /// Stable skill name. + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// Human-readable description of what the skill teaches the model. + [JsonPropertyName("description")] + public required string Description { get; set; } + + /// + /// Whether users can invoke the skill explicitly. When unset, the runtime default is . + /// + [JsonPropertyName("userInvocable")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? UserInvocable { get; set; } + + /// + /// Whether model-initiated invocation is disabled. When unset, the runtime default is . + /// + [JsonPropertyName("disableModelInvocation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? DisableModelInvocation { get; set; } + + /// Optional argument hint shown for explicit invocations. + [JsonPropertyName("argumentHint")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? ArgumentHint { get; set; } +} + +/// +/// Provides session-scoped skills to the Copilot runtime. +/// +/// +/// Experimental. Implementations can be called concurrently and must be safe for +/// concurrent use. The provider is not persisted; supply it again when resuming a +/// session. Returning from +/// reports that the requested skill was not found. +/// +[Experimental(Diagnostics.Experimental)] +public interface ISkillProvider +{ + /// Lists the skills currently available from this provider. + /// + /// Cancels when the runtime abandons the request (for example, on timeout, session disposal, + /// or provider replacement on resume) or the connection closes. + /// + /// The available skill descriptors. + Task> ListSkillsAsync(CancellationToken cancellationToken); + + /// Reads the SKILL.md markdown for a named skill. + /// The skill name requested by the runtime. + /// + /// Cancels when the runtime abandons the request (for example, on timeout, session disposal, + /// or provider replacement on resume) or the connection closes. + /// + /// The skill markdown, or when the skill is not found. + Task ReadSkillAsync(string name, CancellationToken cancellationToken); +} + /// /// Log level for the Copilot runtime. Use the well-known values exposed as /// static members (, , , @@ -890,6 +958,21 @@ public sealed class ToolInvocation /// issuing its own RPC. null for every other tool invocation. /// public IList? AvailableTools { get; set; } + /// + /// Sub-agent instance that issued this call (the + /// of its session events). null for a root-agent call, and for every call + /// when the runtime does not attribute sub-agent tool calls. + /// + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public string? AgentId { get; set; } + /// + /// Runtime request id of this call: the key session.tools.handlePendingToolCall + /// and session.tools.listPendingRequests use. A root-agent call stays answerable + /// after the session is resumed with pending work continued; a sub-agent's call can + /// be answered only while that sub-agent is still running. + /// + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public string? RequestId { get; set; } } /// @@ -3048,6 +3131,12 @@ public sealed class McpHttpServerConfig : McpServerConfig /// public sealed class CustomAgentConfig { + /// + /// Declarative hook actions keyed by event name, active only for this agent. + /// + [JsonPropertyName("hooks")] + public IDictionary>>? Hooks { get; set; } + /// /// Unique name of the custom agent. /// @@ -3193,6 +3282,21 @@ public sealed class LargeToolOutputConfig public string? OutputDirectory { get; set; } } +/// Non-persisted opt-in to image generation. +/// Experimental. This API may change or be removed in a future release. +[Experimental(Diagnostics.Experimental)] +public sealed class ImageGenerationConfig +{ + /// + /// Opt in to an authorized Copilot image model. False disables image generation. + /// Omission disables on create/cold resume and preserves resident resume state. + /// Not persisted: re-supply after runtime restart. Policy, permissions, offline + /// mode, and tool filters still apply. BYOK image generation is not supported. + /// + [JsonPropertyName("enabled")] + public bool? Enabled { get; set; } +} + /// /// Overrides the runtime's built-in tool-search behavior. /// Defers tools to keep the model's active tool set small. @@ -3423,6 +3527,14 @@ public sealed class ManagedSettingsPermissions [JsonPropertyName("disableBypassPermissionsMode")] public string? DisableBypassPermissionsMode { get; set; } + /// + /// When , prevents Assisted Permissions from being + /// activated. Omit or set to to impose no restriction. + /// Serialized as disableAssistedPermissionsMode. + /// + [JsonPropertyName("disableAssistedPermissionsMode")] + public bool? DisableAssistedPermissionsMode { get; set; } + /// Tool-permission patterns that are always denied. [JsonPropertyName("deny")] public IList? Deny { get; set; } @@ -3434,6 +3546,15 @@ public sealed class ManagedSettingsPermissions /// Tool-permission patterns that are allowed without prompting. [JsonPropertyName("allow")] public IList? Allow { get; set; } + + /// + /// Closed-world host boundary expressed as Domain(hostname), + /// Domain(IP), or Domain(*.example.com) rules. Schemes, ports, + /// paths, queries, and fragments are rejected. Multiple managed layers + /// intersect their lists. A present empty list denies all hosts. + /// + [JsonPropertyName("limitTo")] + public IList? LimitTo { get; set; } } /// @@ -3530,6 +3651,7 @@ protected SessionConfigBase(SessionConfigBase? other) InfiniteSessions = other.InfiniteSessions; LargeOutput = other.LargeOutput; ToolSearch = other.ToolSearch; + ImageGeneration = other.ImageGeneration; Memory = other.Memory; McpServers = other.McpServers is not null ? (other.McpServers is Dictionary dict @@ -3571,7 +3693,9 @@ protected SessionConfigBase(SessionConfigBase? other) : null; ExpAssignments = other.ExpAssignments; EnableManagedSettings = other.EnableManagedSettings; + EnforceManagedModelDefaults = other.EnforceManagedModelDefaults; ManagedSettings = other.ManagedSettings; + SkillProvider = other.SkillProvider; #pragma warning disable GHCP001 Canvases = other.Canvases is not null ? [.. other.Canvases] : null; RequestCanvasRenderer = other.RequestCanvasRenderer; @@ -3582,6 +3706,8 @@ protected SessionConfigBase(SessionConfigBase? other) CanvasHandler = other.CanvasHandler; #pragma warning restore GHCP001 SkillDirectories = other.SkillDirectories is not null ? [.. other.SkillDirectories] : null; + AgentDirectories = other.AgentDirectories is not null ? [.. other.AgentDirectories] : null; + HookDirectories = other.HookDirectories is not null ? [.. other.HookDirectories] : null; PluginDirectories = other.PluginDirectories is not null ? [.. other.PluginDirectories] : null; InstructionDirectories = other.InstructionDirectories is not null ? [.. other.InstructionDirectories] : null; SessionLimits = other.SessionLimits; @@ -3686,9 +3812,9 @@ protected SessionConfigBase(SessionConfigBase? other) public bool? EnableOnDemandInstructionDiscovery { get; set; } /// - /// When , enables loading of file-based hooks from - /// .github/hooks/. This is separate from , which - /// controls SDK hook callback registration. + /// When , enables repository-origin file hooks from + /// .github/hooks/ and trusted repository-configured roots. + /// Does not control explicit or callback . /// public bool? EnableFileHooks { get; set; } @@ -3714,6 +3840,20 @@ protected SessionConfigBase(SessionConfigBase? other) /// public bool? EnableSkills { get; set; } + /// + /// Session-scoped skill provider. When set, the runtime can list and read + /// skills by calling back into this SDK host. + /// + /// + /// Experimental. The provider is ephemeral and is never persisted; supply it + /// again when resuming a session. In , + /// set to to make provider + /// skills active. Providers can be called concurrently. + /// + [JsonIgnore] + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public ISkillProvider? SkillProvider { get; set; } + /// /// Built-in skill names to include in the session. In /// , omitting this option excludes all @@ -3963,9 +4103,34 @@ protected SessionConfigBase(SessionConfigBase? other) /// public string? Agent { get; set; } - /// Directories to load skills from. + /// Explicit discovery-only skill roots, not general filesystem grants. + /// + /// Available without , subject to skill/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// ; retained roots do not move when it changes. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// public IList? SkillDirectories { get; set; } + /// Explicit discovery-only agent roots, separate from . + /// + /// No general filesystem grant. Available without , + /// subject to source/managed disables. Relative paths resolve once when supplied against + /// the request's effective ; retained roots do not move. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// + public IList? AgentDirectories { get; set; } + + /// Explicit discovery-only file-hook roots, separate from callback . + /// + /// No general filesystem grant. Available without or + /// (repository-origin hooks only), subject to hook/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// ; retained roots do not move when it changes. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// + public IList? HookDirectories { get; set; } + /// /// Local filesystem paths to Open Plugins-format directories /// (https://open-plugins.com/) to load for this session. @@ -3977,7 +4142,13 @@ protected SessionConfigBase(SessionConfigBase? other) /// public IList? PluginDirectories { get; set; } - /// Additional directories to search for custom instruction files. + /// Explicit discovery-only instruction roots using existing SDK formats. + /// + /// No general filesystem grant. Available without , + /// subject to instruction/managed disables. Relative paths resolve once when supplied + /// against the request's effective ; retained roots do not move. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// public IList? InstructionDirectories { get; set; } /// List of skill names to disable. @@ -4021,6 +4192,10 @@ protected SessionConfigBase(SessionConfigBase? other) /// public ToolSearchConfig? ToolSearch { get; set; } + /// Non-persisted image generation opt-in. Re-supply after runtime restart. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public ImageGenerationConfig? ImageGeneration { get; set; } + /// /// Configuration for session memory. When set, controls whether the /// session can read and write persistent memory. @@ -4099,6 +4274,13 @@ protected SessionConfigBase(SessionConfigBase? other) /// public bool? EnableManagedSettings { get; set; } + /// + /// When true, enforces locked managed model controls for this session. + /// Conflicting model changes are rejected; overridable managed defaults + /// remain mutable. + /// + public bool? EnforceManagedModelDefaults { get; set; } + /// /// Optional managed-settings layer injected at session bootstrap. Currently /// carries a permissions object that composes restrictively with any @@ -4197,6 +4379,7 @@ private SessionConfig(SessionConfig? other) : base(other) if (other is null) return; SessionId = other.SessionId; + Name = other.Name; Cloud = other.Cloud; RefreshCustomInstructions = other.RefreshCustomInstructions; } @@ -4204,6 +4387,15 @@ private SessionConfig(SessionConfig? other) : base(other) /// Optional session identifier; a new ID is generated if not provided. public string? SessionId { get; set; } + /// + /// Names the session at creation, as session.name.set would, and is validated the + /// same way: non-empty, no leading or trailing whitespace, at most 100 UTF-16 units, no + /// control characters, and no double quotes. A name also makes the session persist from + /// the start, so it can be listed and resumed without ever running a turn. + /// Local sessions only: cloud creation rejects it. + /// + public string? Name { get; set; } + /// /// Creates a remote session in the cloud instead of a local session. /// The optional repository is associated with the cloud session. @@ -4877,6 +5069,7 @@ public sealed class SystemMessageTransformRpcResponse [JsonSerializable(typeof(SectionOverride))] [JsonSerializable(typeof(SessionMetadata))] [JsonSerializable(typeof(SetForegroundSessionResponse))] +[JsonSerializable(typeof(SkillProviderDescriptor))] [JsonSerializable(typeof(SystemMessageConfig))] [JsonSerializable(typeof(ToolBinaryResult))] [JsonSerializable(typeof(ToolBinaryResultType))] diff --git a/dotnet/test/E2E/ClientOptionsE2ETests.cs b/dotnet/test/E2E/ClientOptionsE2ETests.cs index d15dccc457..2c3888011d 100644 --- a/dotnet/test/E2E/ClientOptionsE2ETests.cs +++ b/dotnet/test/E2E/ClientOptionsE2ETests.cs @@ -278,6 +278,7 @@ public async Task Should_Forward_Granular_Multitenancy_Fields_In_Create_Wire_Req var session = await Ctx.CreateSessionAsync(client, new SessionConfig { + Name = "named at create", SkipEmbeddingRetrieval = false, OrganizationCustomInstructions = "Follow org policy.", EnableOnDemandInstructionDiscovery = true, @@ -291,6 +292,7 @@ public async Task Should_Forward_Granular_Multitenancy_Fields_In_Create_Wire_Req using var capture = JsonDocument.Parse(await File.ReadAllTextAsync(capturePath)); var createRequest = GetCapturedRequestParams(capture.RootElement, "session.create"); + Assert.Equal("named at create", createRequest.GetProperty("name").GetString()); Assert.False(createRequest.GetProperty("skipEmbeddingRetrieval").GetBoolean()); Assert.Equal("Follow org policy.", createRequest.GetProperty("organizationCustomInstructions").GetString()); Assert.True(createRequest.GetProperty("enableOnDemandInstructionDiscovery").GetBoolean()); @@ -537,6 +539,7 @@ public async Task Should_Apply_Empty_Mode_Defaults_To_CreateSession_Wire_Request Assert.False(createRequest.GetProperty("enableSkills").GetBoolean()); Assert.True(createRequest.GetProperty("customAgentsLocalOnly").GetBoolean()); Assert.False(createRequest.TryGetProperty("organizationCustomInstructions", out _)); + Assert.False(createRequest.TryGetProperty("name", out _)); await session.DisposeAsync(); } diff --git a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs index cdbfe82ae8..f6b539fa9d 100644 --- a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs +++ b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs @@ -21,6 +21,7 @@ public class PendingWorkResumeE2ETests(E2ETestFixture fixture, ITestOutputHelper [Fact] public async Task Should_Continue_Pending_Permission_Request_After_Resume() + => await WithSdkDiagnosticsAsync(async () => { var originalPermissionRequest = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var releaseOriginalPermission = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -54,7 +55,7 @@ await session1.SendAsync(new MessageOptions var permissionEvent = await permissionRequested; Assert.IsType(initialRequest); - await suspendedClient.ForceStopAsync(); + await ForceStopAfterSessionLockObservedAsync(suspendedClient, sessionId); await using var resumedTcpClient = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForUri(cliUrl, connectionToken: SharedToken) }); var session2 = await Ctx.ResumeSessionAsync(resumedTcpClient, sessionId, new ResumeSessionConfig @@ -69,6 +70,8 @@ await session1.SendAsync(new MessageOptions "resume_permission_tool") ], }); + var resumeEvent = await GetSingleResumeEventAsync(session2); + Assert.False(resumeEvent.Data.SessionWasActive); var permissionResult = await session2.Rpc.Permissions.HandlePendingPermissionRequestAsync( permissionEvent.Data.RequestId, @@ -86,10 +89,11 @@ await session1.SendAsync(new MessageOptions [Description("Transforms a value after permission is granted")] static string ResumePermissionTool([Description("Value to transform")] string value) => $"ORIGINAL_SHOULD_NOT_RUN_{value}"; - } + }); [Fact] public async Task Should_Continue_Pending_External_Tool_Request_After_Resume() + => await WithSdkDiagnosticsAsync(async () => { var originalToolStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var releaseOriginalTool = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -154,7 +158,7 @@ async Task BlockingExternalTool( originalToolStarted.TrySetResult(value); return await releaseOriginalTool.Task.WaitAsync(Timeout.InfiniteTimeSpan, cancellationToken); } - } + }); [Fact] public Task Should_Keep_Pending_External_Tool_Handleable_On_Warm_Resume_When_ContinuePendingWork_Is_False() => @@ -170,10 +174,39 @@ public Task Should_Keep_Pending_External_Tool_Handleable_On_Cold_Resume_When_Con expectedSessionWasActive: false, expectedHandleResult: false); + private async Task ForceStopAfterSessionLockObservedAsync(CopilotClient suspendedClient, string sessionId) + { + await using var lockObserver = Ctx.CreateClient(options: new CopilotClientOptions + { + Connection = RuntimeConnection.ForStdio(), + }); + await lockObserver.StartAsync(); + await TestHelper.WaitForConditionAsync( + async () => + { + var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); + return result.InUse.Contains(sessionId); + }, + timeout: PendingWorkTimeout, + timeoutMessage: $"Timed out waiting for session '{sessionId}' to acquire its lock."); + + await suspendedClient.ForceStopAsync(); + + await TestHelper.WaitForConditionAsync( + async () => + { + var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); + return !result.InUse.Contains(sessionId); + }, + timeout: PendingWorkTimeout, + timeoutMessage: $"Timed out waiting for session '{sessionId}' to release its lock."); + } + private async Task AssertPendingExternalToolHandleableOnResumeAsync( bool disconnectOriginalClient, bool expectedSessionWasActive, bool expectedHandleResult) + => await WithSdkDiagnosticsAsync(async () => { var originalToolStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var releaseOriginalTool = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -210,30 +243,7 @@ await session1.SendAsync(new MessageOptions if (disconnectOriginalClient) { - await using var lockObserver = Ctx.CreateClient(options: new CopilotClientOptions - { - Connection = RuntimeConnection.ForStdio(), - }); - await lockObserver.StartAsync(); - await TestHelper.WaitForConditionAsync( - async () => - { - var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); - return result.InUse.Contains(sessionId); - }, - timeout: PendingWorkTimeout, - timeoutMessage: $"Timed out waiting for session '{sessionId}' to acquire its lock."); - - await suspendedClient.ForceStopAsync(); - - await TestHelper.WaitForConditionAsync( - async () => - { - var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); - return !result.InUse.Contains(sessionId); - }, - timeout: PendingWorkTimeout, - timeoutMessage: $"Timed out waiting for session '{sessionId}' to release its lock."); + await ForceStopAfterSessionLockObservedAsync(suspendedClient, sessionId); } await using var resumedClient = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForUri(cliUrl, connectionToken: SharedToken) }); @@ -307,10 +317,11 @@ async Task BlockingExternalTool( [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] public async Task Should_Continue_Parallel_Pending_External_Tool_Requests_After_Resume() + => await WithSdkDiagnosticsAsync(async () => { var originalToolAStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var originalToolBStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -441,7 +452,7 @@ async Task BlockingToolB( originalToolBStarted.TrySetResult(value); return await releaseOriginalToolB.Task.WaitAsync(Timeout.InfiniteTimeSpan, cancellationToken); } - } + }); [Fact] public async Task Should_Resume_Successfully_When_No_Pending_Work_Exists() diff --git a/dotnet/test/E2E/PermissionE2ETests.cs b/dotnet/test/E2E/PermissionE2ETests.cs index 78e792c2c2..77b0e588ff 100644 --- a/dotnet/test/E2E/PermissionE2ETests.cs +++ b/dotnet/test/E2E/PermissionE2ETests.cs @@ -5,6 +5,7 @@ using GitHub.Copilot.Rpc; using GitHub.Copilot.Test.Harness; using Microsoft.Extensions.AI; +using Microsoft.Extensions.Logging; using System.Text.Json; using System.Text.Json.Serialization; using Xunit; @@ -173,23 +174,64 @@ internal static async Task AssertApproveAllPermissionHandlerAsync(CopilotSession [Fact] public async Task Should_Handle_Async_Permission_Handler() { + await Ctx.ConfigureForTestAsync("permissions", "Should_Handle_Async_Permission_Handler_Dotnet"); + + const string toolName = "async_permission_echo"; + const string expectedResult = "DOTNET_ASYNC_PERMISSION_RESULT"; var permissionRequestReceived = false; - var session = await CreateSessionAsync(new SessionConfig + var toolCalls = 0; + string? permissionToolCallId = null; + CopilotSession? session = null; + session = await CreateSessionAsync(new SessionConfig { + Tools = + [ + AIFunctionFactory.Create( + Echo, + toolName, + "Returns the result for the asynchronous permission test.", + serializerOptions: PermissionJsonContext.Default.Options), + ], + AvailableTools = [toolName], OnPermissionRequest = async (request, invocation) => { - permissionRequestReceived = true; + var customToolRequest = Assert.IsType(request); + Assert.Equal(toolName, customToolRequest.ToolName); + Assert.Equal(session!.SessionId, invocation.SessionId); + Assert.False(string.IsNullOrWhiteSpace(customToolRequest.ToolCallId)); + permissionToolCallId = customToolRequest.ToolCallId; await Task.Yield(); + permissionRequestReceived = true; return PermissionDecision.ApproveOnce(); } }); - await TestHelper.SendAndGetFinalAssistantMessageAsync(session, new MessageOptions + ToolExecutionCompleteEvent? toolCompleted = null; + using var subscription = session.On(evt => + { + if (evt.Data.ToolCallId == permissionToolCallId) + { + toolCompleted = evt; + } + }); + var message = await TestHelper.SendAndGetFinalAssistantMessageAsync(session, new MessageOptions { - Prompt = "Run 'echo test' and tell me what happens" + Prompt = "Call async_permission_echo once and reply with only its returned text." }); Assert.True(permissionRequestReceived, "Permission request should have been received"); + Assert.Equal(1, toolCalls); + Assert.NotNull(toolCompleted); + Assert.True(toolCompleted.Data.Success); + Assert.Equal(expectedResult, toolCompleted.Data.Result?.Content); + Assert.Contains(expectedResult, message.Data.Content); + + string Echo() + { + Assert.True(permissionRequestReceived, "The yielding permission handler must finish before the tool runs."); + Interlocked.Increment(ref toolCalls); + return expectedResult; + } } [Fact] @@ -330,6 +372,7 @@ public async Task Should_Receive_ToolCallId_In_Permission_Requests() [Fact] public async Task Should_Wait_For_Slow_Permission_Handler() + => await WithSdkDiagnosticsAsync(async () => { var handlerEntered = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var releaseHandler = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -388,7 +431,21 @@ void AddLifecycleEvent(string phase, string? toolCallId) releaseHandler.SetResult(); - var message = await sendTask; + AssistantMessageEvent? message; + try + { + message = await sendTask; + } + catch (TimeoutException) + { + lock (lifecycleLock) + { + Logger.LogWarning( + "Slow-permission timeout lifecycle: {Lifecycle}", + string.Join(", ", lifecycle.Select(evt => $"{evt.Phase}:{evt.ToolCallId}"))); + } + throw; + } var persistedEvents = await WaitForPersistedEventsAsync( session, events => @@ -424,7 +481,7 @@ void AddLifecycleEvent(string phase, string? toolCallId) // The tool should have actually run after permission was granted Assert.Contains("slow_handler_test", message?.Data.Content ?? string.Empty); - } + }); [Fact] public async Task Should_Handle_Concurrent_Permission_Requests_From_Parallel_Tools() diff --git a/dotnet/test/E2E/RuntimeHostE2ETests.cs b/dotnet/test/E2E/RuntimeHostE2ETests.cs index 231f29c733..690e925653 100644 --- a/dotnet/test/E2E/RuntimeHostE2ETests.cs +++ b/dotnet/test/E2E/RuntimeHostE2ETests.cs @@ -44,6 +44,8 @@ private sealed class Application(E2ETestContext context, CopilotClient client) public CopilotSession? Session; public int Creates; public int Resumes; + public string? CreateSessionId; + public string? ResumeSessionId; public int ToolCalls; public readonly ConcurrentQueue HookSessions = new(); public readonly ConcurrentQueue Releases = new(); @@ -82,8 +84,12 @@ private string MagicNumber([Description("A seed value")] string seed) Interlocked.Increment(ref Creates); Assert.False(request.CancellationToken.IsCancellationRequested); Assert.Equal(context.WorkDir, request.Config.WorkingDirectory); + CreateSessionId = request.Config.SessionId; + Assert.False(string.IsNullOrEmpty(CreateSessionId)); Configure(request.Config); - return Session = await context.CreateSessionAsync(client, request.Config); + Session = await context.CreateSessionAsync(client, request.Config); + Assert.Equal(CreateSessionId, Session.SessionId); + return Session; }, ResumeSession = async request => { @@ -91,8 +97,11 @@ private string MagicNumber([Description("A seed value")] string seed) Assert.False(request.CancellationToken.IsCancellationRequested); Assert.False(request.Config.ContinuePendingWork); Assert.Equal(context.WorkDir, request.Config.WorkingDirectory); + ResumeSessionId = request.SessionId; Configure(request.Config); - return Session = await context.ResumeSessionAsync(client, request.SessionId, request.Config); + Session = await context.ResumeSessionAsync(client, request.SessionId, request.Config); + Assert.Equal(ResumeSessionId, Session.SessionId); + return Session; }, OnSessionReleased = session => { @@ -166,7 +175,8 @@ public async Task Creates_Or_Publishes_Exact_Application_Session(bool publish) var created = await ahp.RequestAsync(new() { ["op"] = "create", ["clientId"] = clientId, ["workDir"] = Ctx.WorkDir }); sessionId = created.GetProperty("sessionId").GetString()!; Assert.Equal(1, app.Creates); - Assert.Equal(sessionId, app.Session!.SessionId); + Assert.Equal(app.CreateSessionId, app.Session!.SessionId); + Assert.NotEqual(sessionId, app.Session.SessionId); } var response = await ahp.RequestAsync(new() { @@ -176,7 +186,7 @@ public async Task Creates_Or_Publishes_Exact_Application_Session(bool publish) ["prompt"] = ToolPrompt }); Assert.Contains("MAGIC_hello_42", response.GetProperty("text").GetString()); - await AssertApplicationAsync(app, sessionId); + await AssertApplicationAsync(app, app.Session!.SessionId); await Task.WhenAll(host.DisposeAsync().AsTask(), host.DisposeAsync().AsTask()); await ahp.RequestAsync(new() { ["op"] = "stopped", ["clientId"] = clientId, ["url"] = host.Url }); if (publish) @@ -215,6 +225,9 @@ public async Task Resumes_After_Runtime_Restart_And_Composes_Tools() ["clientTools"] = true }); sessionId = created.GetProperty("sessionId").GetString()!; + Assert.Equal(1, first.Creates); + Assert.Equal(first.CreateSessionId, first.Session!.SessionId); + Assert.NotEqual(sessionId, first.Session.SessionId); var answer = await ahp.RequestAsync(new() { ["op"] = "turn", @@ -247,7 +260,8 @@ public async Task Resumes_After_Runtime_Restart_And_Composes_Tools() .Select(turn => turn.GetProperty("message").GetProperty("text").GetString())); Assert.Equal(0, resumed.Creates); Assert.Equal(1, resumed.Resumes); - Assert.Equal(sessionId, resumed.Session!.SessionId); + Assert.Equal(first.Session!.SessionId, resumed.ResumeSessionId); + Assert.Equal(first.Session.SessionId, resumed.Session!.SessionId); Assert.NotSame(first.Session, resumed.Session); var response = await ahp.RequestAsync(new() { @@ -260,7 +274,7 @@ public async Task Resumes_After_Runtime_Restart_And_Composes_Tools() Assert.Contains("MAGIC_hello_42", response.GetProperty("text").GetString()); Assert.Contains("CLIENT_ECHO_ping", response.GetProperty("text").GetString()); Assert.Equal(1, response.GetProperty("clientToolCalls").GetInt32()); - await AssertApplicationAsync(resumed, sessionId); + await AssertApplicationAsync(resumed, first.Session.SessionId); await replacement.DisposeAsync(); await ahp.RequestAsync(new() { ["op"] = "stopped", ["clientId"] = clientId, ["url"] = replacement.Url }); await resumed.Released.Task.WaitAsync(TimeSpan.FromSeconds(10)); diff --git a/dotnet/test/E2E/ScenarioTestingProvidersE2ETests.cs b/dotnet/test/E2E/ScenarioTestingProvidersE2ETests.cs index 13270d3e43..da8f0eccf2 100644 --- a/dotnet/test/E2E/ScenarioTestingProvidersE2ETests.cs +++ b/dotnet/test/E2E/ScenarioTestingProvidersE2ETests.cs @@ -281,7 +281,7 @@ public async Task Should_Ignore_Failing_Unselected_Provider_But_Surface_Selected Prompt = "This selected provider should fail.", })); Assert.Contains("offline", failure.ToString(), StringComparison.OrdinalIgnoreCase); - Assert.Contains(handler.InferenceRequests, request => request.Host == "offline.scenario.invalid"); + Assert.Single(handler.InferenceRequests, request => request.Host == "offline.scenario.invalid"); } private CopilotClient CreateProviderClient(ScenarioProviderRequestHandler handler) => @@ -385,7 +385,8 @@ protected override async Task SendRequestAsync( if (string.Equals(uri.Host, failingHost, StringComparison.Ordinal)) { - return new HttpResponseMessage(HttpStatusCode.BadGateway) + // Provider selection is the contract here, not transient-error retry backoff. + return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent( "{\"error\":{\"message\":\"offline scenario provider\"}}", diff --git a/dotnet/test/E2E/SessionE2ETests.cs b/dotnet/test/E2E/SessionE2ETests.cs index 9855bc8eae..c3b9e7bdd9 100644 --- a/dotnet/test/E2E/SessionE2ETests.cs +++ b/dotnet/test/E2E/SessionE2ETests.cs @@ -476,15 +476,22 @@ public async Task Should_Receive_Session_Events() [Fact] public async Task Send_Returns_Immediately_While_Events_Stream_In_Background() + => await WithSdkDiagnosticsAsync(async () => { - var session = await CreateSessionAsync(new SessionConfig + // Reuse a custom-tool capture instead of depending on a native shell completing within its wait. + await Ctx.ConfigureForTestAsync( + "pending_work_resume", "should_continue_pending_external_tool_request_after_resume", replayOnly: true); + var toolStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var releaseTool = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + await using var session = await CreateSessionAsync(new SessionConfig { + Tools = [AIFunctionFactory.Create(BlockingTool, "resume_external_tool")], OnPermissionRequest = PermissionHandler.ApproveAll, }); var events = new ConcurrentQueue(); AssistantMessageEvent? message = null; - session.On(evt => + using var subscription = session.On(evt => { events.Enqueue(evt.Type); if (evt is AssistantMessageEvent assistantMessage) @@ -494,19 +501,36 @@ public async Task Send_Returns_Immediately_While_Events_Stream_In_Background() }); var idle = TestHelper.GetNextEventOfTypeAsync(session); - // Use a slow command so we can verify SendAsync() returns before completion - await session.SendAsync(new MessageOptions { Prompt = "Run 'sleep 2 && echo done'" }); - - // SendAsync() should return before turn completes (no session.idle yet) - Assert.DoesNotContain("session.idle", events); - - // Wait for turn to complete - await idle; + try + { + var send = session.SendAsync(new MessageOptions + { + Prompt = "Use resume_external_tool with value 'beta', then reply with the result.", + }); + Assert.Equal("beta", await toolStarted.Task.WaitAsync(TimeSpan.FromSeconds(60))); + await send.WaitAsync(TimeSpan.FromSeconds(60)); + Assert.DoesNotContain("session.idle", events); + Assert.False(idle.IsCompleted); + + releaseTool.TrySetResult("EXTERNAL_RESUMED_BETA"); + await idle; + + Assert.Contains("EXTERNAL_RESUMED_BETA", message?.Data.Content ?? string.Empty); + Assert.Contains("session.idle", events); + Assert.Contains("assistant.message", events); + } + finally + { + releaseTool.TrySetResult("EXTERNAL_RESUMED_BETA"); + } - Assert.Contains("done", message?.Data.Content ?? string.Empty); - Assert.Contains("session.idle", events); - Assert.Contains("assistant.message", events); - } + [Description("Blocks until the test releases the active turn")] + async Task BlockingTool([Description("Value to return")] string value, CancellationToken cancellationToken) + { + toolStarted.TrySetResult(value); + return await releaseTool.Task.WaitAsync(Timeout.InfiniteTimeSpan, cancellationToken); + } + }); [Fact] public async Task SendAndWait_Blocks_Until_Session_Idle_And_Returns_Final_Assistant_Message() diff --git a/dotnet/test/E2E/SkillProviderE2ETests.cs b/dotnet/test/E2E/SkillProviderE2ETests.cs new file mode 100644 index 0000000000..3b2d593824 --- /dev/null +++ b/dotnet/test/E2E/SkillProviderE2ETests.cs @@ -0,0 +1,418 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +using System.Collections.Concurrent; +using System.Reflection; +using GitHub.Copilot.Rpc; +using Xunit; +using Xunit.Abstractions; + +namespace GitHub.Copilot.Test.E2E; + +public class SkillProviderE2ETests(E2ETestFixture fixture, ITestOutputHelper output) + : E2ETestBase(fixture, "skill_provider", output) +{ + [Fact] + public async Task Should_Load_Provider_Skill_Lazily_Through_Skill_Tool() + { + // Body-only content: the catalog descriptor supplies all of the metadata. + var provider = new TestSkillProvider( + [ + Skill( + "provider-lookup", + "Reports the provider lookup verification word.", + "# Provider lookup\n\nThe verification word is TANGERINE_QUARTZ_19. Reply with it.\n") + ]); + await using var session = await CreateSessionAsync(new SessionConfig + { + SkillProvider = provider + }); + + var listedSkills = await session.Rpc.Skills.ListAsync(); + var listed = Assert.Single(listedSkills.Skills, skill => skill.Name == "provider-lookup"); + Assert.Equal(SkillSource.Sdk, listed.Source); + Assert.True(listed.Enabled); + Assert.True(string.IsNullOrEmpty(listed.Path)); + Assert.Empty(provider.Reads); + + var message = await session.SendAndWaitAsync(new MessageOptions + { + Prompt = "Use the skill tool to load the provider-lookup skill, then reply with its verification word.", + }, TimeSpan.FromMinutes(3)); + + Assert.Equal(["provider-lookup"], provider.Reads); + Assert.NotNull(message); + // Validate the final assistant response arrived (guards against truncated captures) + Assert.Contains("TANGERINE_QUARTZ_19", message!.Data.Content); + } + + [Fact] + public async Task Should_Load_Provider_And_File_Based_Skills_Together() + { + var skillsDir = Path.Join(Ctx.WorkDir, "file-skills"); + if (Directory.Exists(skillsDir)) + { + Directory.Delete(skillsDir, recursive: true); + } + + Directory.CreateDirectory(Path.Join(skillsDir, "file-notes")); + File.WriteAllText( + Path.Join(skillsDir, "file-notes", "SKILL.md"), + "---\nname: file-notes\ndescription: Reports the file notes verification word.\n---\n\nThe file notes verification word is MAPLE_FALCON_27.\n"); + + // Frontmatter may restate catalog metadata and is the only source of allowed-tools. + var provider = new TestSkillProvider( + [ + Skill( + "provider-audit", + "Reports the provider audit verification word.", + "---\nname: provider-audit\nallowed-tools: view\n---\n\nThe provider audit verification word is COBALT_HERON_58.\n") + ]); + await using var session = await CreateSessionAsync(new SessionConfig + { + SkillDirectories = [skillsDir], + SkillProvider = provider + }); + + var listedSkills = await session.Rpc.Skills.ListAsync(); + var fileSkill = Assert.Single(listedSkills.Skills, skill => skill.Name == "file-notes"); + var providerSkill = Assert.Single(listedSkills.Skills, skill => skill.Name == "provider-audit"); + Assert.NotEqual(SkillSource.Sdk, fileSkill.Source); + Assert.False(string.IsNullOrWhiteSpace(fileSkill.Path)); + Assert.Equal(SkillSource.Sdk, providerSkill.Source); + + var message = await session.SendAndWaitAsync(new MessageOptions + { + Prompt = "Use the skill tool to load the file-notes skill and the provider-audit skill, then reply with both verification words.", + }, TimeSpan.FromMinutes(3)); + + Assert.Equal(["provider-audit"], provider.Reads); + Assert.NotNull(message); + Assert.Contains("MAPLE_FALCON_27", message!.Data.Content); + // Validate the final assistant response arrived (guards against truncated captures) + Assert.Contains("COBALT_HERON_58", message.Data.Content); + } + + [Fact] + public async Task Should_Rebind_Skill_Provider_On_Resume() + { + var original = new TestSkillProvider( + [ + Skill( + "rebind-check", + "Reports the rebind verification word.", + "The rebind verification word is AMBER_ALPHA_11.\n") + ]); + var replacement = new TestSkillProvider( + [ + Skill( + "rebind-check", + "Reports the rebind verification word.", + "The rebind verification word is BRONZE_BETA_22.\n") + ]); + var first = await CreateSessionAsync(new SessionConfig + { + SkillProvider = original + }); + var sessionId = first.SessionId; + var ready = await first.SendAndWaitAsync(new MessageOptions + { + Prompt = "Without using any tools or skills, reply with exactly REBIND_READY.", + }, TimeSpan.FromMinutes(3)); + Assert.NotNull(ready); + Assert.Contains("REBIND_READY", ready!.Data.Content); + + await first.DisposeAsync(); + Assert.Empty(original.Reads); + var originalCallsBeforeResume = original.Calls.Count; + + await using var session = await ResumeSessionAsync(sessionId, new ResumeSessionConfig + { + SkillProvider = replacement + }); + + var message = await session.SendAndWaitAsync(new MessageOptions + { + Prompt = "Use the skill tool to load the rebind-check skill, then reply with its verification word.", + }, TimeSpan.FromMinutes(3)); + + Assert.Equal(["rebind-check"], replacement.Reads); + Assert.Equal(originalCallsBeforeResume, original.Calls.Count); + Assert.NotNull(message); + // Validate the final assistant response arrived (guards against truncated captures) + Assert.Contains("BRONZE_BETA_22", message!.Data.Content); + Assert.DoesNotContain("AMBER_ALPHA_11", message.Data.Content); + } + + [Fact] + public async Task Should_Report_Provider_Read_Failure_Without_Leaking_Details() + { + const string secret = "PROVIDER_SECRET_7F3A9C"; + var provider = new TestSkillProvider( + [ + new ProvidedSkill( + new SkillProviderDescriptor + { + Name = "broken-lookup", + Description = "Reports the broken lookup verification word.", + }, + () => throw new InvalidOperationException($"database unavailable: {secret}")) + ]); + var events = new ConcurrentQueue(); + await using var session = await CreateSessionAsync(new SessionConfig + { + SkillProvider = provider, + OnEvent = events.Enqueue + }); + + var message = await session.SendAndWaitAsync(new MessageOptions + { + Prompt = "Use the skill tool to load the broken-lookup skill. If loading fails, reply with exactly LOAD_FAILED.", + }, TimeSpan.FromMinutes(3)); + + Assert.Contains("broken-lookup", provider.Reads); + var failures = events + .OfType() + .Where(evt => !evt.Data.Success) + .ToArray(); + var failure = Assert.Single(failures); + Assert.DoesNotContain(secret, string.Join("\n", events.Select(evt => evt.ToJson())), StringComparison.Ordinal); + Assert.NotNull(failure.Data.Error); + Assert.NotNull(message); + // Validate the final assistant response arrived (guards against truncated captures) + Assert.Contains("LOAD_FAILED", message!.Data.Content); + } + + [Fact] + public async Task Should_Report_Missing_Provider_Skill_As_Not_Found() + { + var provider = new TestSkillProvider( + [ + new ProvidedSkill( + new SkillProviderDescriptor + { + Name = "vanished-lookup", + Description = "Reports the vanished lookup verification word.", + }, + () => null) + ]); + var events = new ConcurrentQueue(); + await using var session = await CreateSessionAsync(new SessionConfig + { + SkillProvider = provider, + OnEvent = events.Enqueue + }); + + var message = await session.SendAndWaitAsync(new MessageOptions + { + Prompt = "Use the skill tool to load the vanished-lookup skill. If loading fails, reply with exactly LOAD_FAILED.", + }, TimeSpan.FromMinutes(3)); + + Assert.Contains("vanished-lookup", provider.Reads); + var failures = events + .OfType() + .Where(evt => !evt.Data.Success) + .ToArray(); + var failure = Assert.Single(failures); + Assert.Contains("not found", failure.ToJson(), StringComparison.OrdinalIgnoreCase); + Assert.NotNull(message); + // Validate the final assistant response arrived (guards against truncated captures) + Assert.Contains("LOAD_FAILED", message!.Data.Content); + } + + [Fact] + public async Task Should_Keep_Provider_Dormant_When_Skills_Disabled() + { + var provider = new TestSkillProvider( + [ + Skill("dormant-lookup", "Never listed.", "Never read.\n") + ]); + await using var session = await CreateSessionAsync(new SessionConfig + { + EnableSkills = false, + SkillProvider = provider + }); + + await session.Rpc.Skills.EnsureLoadedAsync(); + var listedSkills = await session.Rpc.Skills.ListAsync(); + + Assert.DoesNotContain(listedSkills.Skills, skill => skill.Source == SkillSource.Sdk); + Assert.Empty(provider.Calls); + } + + [Fact] + public async Task Should_Unbind_Provider_When_Resumed_Without_One() + { + var provider = new TestSkillProvider( + [ + Skill("unbound-lookup", "Reports the unbound lookup word.", "Unbound.\n") + ]); + var first = await CreateSessionAsync(new SessionConfig + { + SkillProvider = provider + }); + var before = await first.Rpc.Skills.ListAsync(); + Assert.Contains(before.Skills, skill => skill.Name == "unbound-lookup"); + var callsBeforeResume = provider.Calls.Count; + + UntrackSessionWithoutDetach(first); + + CopilotSession? session = null; + try + { + session = await Ctx.ResumeSessionAsync(Client, first.SessionId, new ResumeSessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + }); + + await session.Rpc.Skills.ReloadAsync(); + var listedSkills = await session.Rpc.Skills.ListAsync(); + + Assert.DoesNotContain(listedSkills.Skills, skill => skill.Source == SkillSource.Sdk); + Assert.Equal(callsBeforeResume, provider.Calls.Count); + } + finally + { + if (session is not null) + { + await session.DisposeAsync(); + } + + await first.DisposeAsync(); + } + } + + [Fact] + public async Task Should_Cancel_A_Blocked_Provider_Call_When_The_Session_Is_Disposed() + { + var provider = new BlockingSkillProvider(); + var session = await CreateSessionAsync(new SessionConfig + { + SkillProvider = provider + }); + + // The list RPC may fail or omit provider skills once the binding is removed; + // only the provider's cancellation matters here. + var list = session.Rpc.Skills.ListAsync(); + await provider.Entered.WaitAsync(TimeSpan.FromSeconds(30)); + + await session.DisposeAsync(); + + await provider.Cancelled.WaitAsync(TimeSpan.FromSeconds(10)); + await Record.ExceptionAsync(() => list); + } + + [Fact] + public async Task Should_Reject_Skill_Provider_For_Cloud_Sessions() + { + var provider = new TestSkillProvider( + [ + Skill("cloud-lookup", "Never listed.", "Never read.\n") + ]); + + var exception = await Assert.ThrowsAsync(() => + Client.CreateSessionAsync(new SessionConfig + { + Cloud = new CloudSessionOptions(), + SkillProvider = provider, + })); + + Assert.Equal("Skill providers are not supported for cloud sessions.", exception.Message); + Assert.Empty(provider.Calls); + } + + private static ProvidedSkill Skill(string name, string description, string markdown) => + new( + new SkillProviderDescriptor + { + Name = name, + Description = description, + }, + () => markdown); + + private static void UntrackSessionWithoutDetach(CopilotSession session) + { + // Match a warm runtime resume: remove the SDK wrapper so resume is allowed, but do not detach the runtime session. + var removeFromClient = typeof(CopilotSession).GetMethod( + "RemoveFromClient", + BindingFlags.Instance | BindingFlags.NonPublic) + ?? throw new InvalidOperationException("CopilotSession.RemoveFromClient was not found."); + removeFromClient.Invoke(session, null); + } + + private sealed record ProvidedSkill(SkillProviderDescriptor Descriptor, Func Read); + + private sealed class BlockingSkillProvider : ISkillProvider + { + private readonly TaskCompletionSource _entered = new(TaskCreationOptions.RunContinuationsAsynchronously); + private readonly TaskCompletionSource _cancelled = new(TaskCreationOptions.RunContinuationsAsynchronously); + + public Task Entered => _entered.Task; + + public Task Cancelled => _cancelled.Task; + + public async Task> ListSkillsAsync(CancellationToken cancellationToken) + { + _entered.TrySetResult(); + try + { + await Task.Delay(Timeout.Infinite, cancellationToken); + } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + // Not a token callback: if cancellation resumes this method inline, disposing + // a registration whose callback has not run yet drops it. + _cancelled.TrySetResult(); + throw; + } + + return []; + } + + public Task ReadSkillAsync(string name, CancellationToken cancellationToken) => + Task.FromResult(null); + } + + private sealed class TestSkillProvider(IReadOnlyList skills) : ISkillProvider + { + private readonly object _lock = new(); + private readonly List _calls = []; + + public IReadOnlyList Calls + { + get + { + lock (_lock) + { + return [.. _calls]; + } + } + } + + public IReadOnlyList Reads => Calls + .Where(call => call.StartsWith("read:", StringComparison.Ordinal)) + .Select(call => call["read:".Length..]) + .ToArray(); + + public Task> ListSkillsAsync(CancellationToken cancellationToken) + { + AddCall("list"); + return Task.FromResult>(skills.Select(skill => skill.Descriptor).ToArray()); + } + + public Task ReadSkillAsync(string name, CancellationToken cancellationToken) + { + AddCall($"read:{name}"); + return Task.FromResult(skills.FirstOrDefault(skill => skill.Descriptor.Name == name)?.Read()); + } + + private void AddCall(string call) + { + lock (_lock) + { + _calls.Add(call); + } + } + } +} diff --git a/dotnet/test/E2E/StructuredOutputE2ETests.cs b/dotnet/test/E2E/StructuredOutputE2ETests.cs index b18e93b492..e82e31d008 100644 --- a/dotnet/test/E2E/StructuredOutputE2ETests.cs +++ b/dotnet/test/E2E/StructuredOutputE2ETests.cs @@ -392,6 +392,15 @@ public async Task Rejects_Unsupported_Or_Oversized_Schemas_Before_Admission() { var config = StructuredSessionConfig(); config.Model = model; + config.EnableExperimentalMode = model == "hydrafusion"; + if (model == "hydrafusion") + { + config.FeatureFlags = new Dictionary + { + ["HYDRAFUSION"] = true, + ["HYDRAFUSION_ROLLOUT"] = true, + }; + } config.OnPermissionRequest = PermissionHandler.ApproveAll; await using var session = await Ctx.CreateSessionAsync(client, config); await Assert.ThrowsAsync(() => session.SendAndWaitAsync( diff --git a/dotnet/test/GitHub.Copilot.SDK.Test.csproj b/dotnet/test/GitHub.Copilot.SDK.Test.csproj index 3f1c24f973..9c8b6fc9c5 100644 --- a/dotnet/test/GitHub.Copilot.SDK.Test.csproj +++ b/dotnet/test/GitHub.Copilot.SDK.Test.csproj @@ -16,6 +16,12 @@ false + + + $(RuntimeIdentifier) + $(NETCoreSdkPortableRuntimeIdentifier) + + diff --git a/dotnet/test/Harness/E2ETestBase.cs b/dotnet/test/Harness/E2ETestBase.cs index a9b18bf6cf..008bbc8074 100644 --- a/dotnet/test/Harness/E2ETestBase.cs +++ b/dotnet/test/Harness/E2ETestBase.cs @@ -6,6 +6,7 @@ using GitHub.Copilot.Test.Harness; using Microsoft.Extensions.Logging; using System.Data; +using System.Diagnostics; using System.Reflection; using Xunit; using Xunit.Abstractions; @@ -18,6 +19,7 @@ public abstract class E2ETestBase : IClassFixture, IAsyncLifetim private readonly string _snapshotCategory; private readonly string _testName; private readonly bool _replayOnly; + private readonly ITestOutputHelper _output; protected E2ETestContext Ctx => _fixture.Ctx; protected CopilotClient Client => _fixture.Client; @@ -32,10 +34,12 @@ protected E2ETestBase( _snapshotCategory = snapshotCategory; _testName = GetTestName(output); _replayOnly = replayOnly; + _output = output; Logger = new XunitLogger(output); // Wire logger into the shared context so all clients created via Ctx.CreateClient get it. Ctx.Logger = Logger; + Ctx.DiagnosticsEnabled = snapshotCategory is "pending_work_resume" or "session" or "permissions"; } /// Logger that forwards warnings and above to xunit test output. @@ -75,6 +79,53 @@ public Task DisposeAsync() return Ctx.CleanupAfterTestAsync(); } + protected async Task WithSdkDiagnosticsAsync(Func test) + { + try + { + await test(); + } + catch + { + using var process = new Process + { + StartInfo = new ProcessStartInfo("node") + { + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }, + }; + var started = false; + try + { + process.StartInfo.Arguments = string.Join(" ", + new[] { Path.Join(FindTestHarnessDir(), "sdk-diagnostics.mjs"), Ctx.HomeDir } + .Select(argument => "\"" + argument.Replace("\"", "\\\"") + "\"")); + process.Start(); + started = true; + var text = process.StandardOutput.ReadToEndAsync(); + var errors = process.StandardError.ReadToEndAsync(); + await Task.WhenAll(text, errors, process.WaitForExitAsync()).WaitAsync(TimeSpan.FromSeconds(5)); + _output.WriteLine(process.ExitCode == 0 ? await text : "SDK diagnostics unavailable"); + } + catch + { + try + { + if (started && !process.HasExited) process.Kill(entireProcessTree: true); + } + catch (Exception error) when (error is InvalidOperationException or System.ComponentModel.Win32Exception) + { + _output.WriteLine("SDK diagnostics collector cleanup failed"); + } + _output.WriteLine("SDK diagnostics unavailable"); + } + throw; + } + } + /// /// Creates a session with a default config that approves all permissions. /// Convenience wrapper for E2E tests. diff --git a/dotnet/test/Harness/E2ETestContext.cs b/dotnet/test/Harness/E2ETestContext.cs index b399372717..f35fe7a659 100644 --- a/dotnet/test/Harness/E2ETestContext.cs +++ b/dotnet/test/Harness/E2ETestContext.cs @@ -25,6 +25,7 @@ public sealed class E2ETestContext : IAsyncDisposable /// Optional logger injected by tests; applied to all clients created via . public ILogger? Logger { get; set; } + public bool DiagnosticsEnabled { get; set; } private readonly ReplayProxy _proxy; private readonly string _repoRoot; @@ -84,7 +85,7 @@ await proxy.ConfigureAsync( await proxy.SetCopilotUserByTokenAsync(DefaultGitHubToken, new CopilotUserConfig( Login: "e2e-test-user", CopilotPlan: "individual_pro", - Endpoints: new CopilotUserEndpoints(Api: context.ProxyUrl, Telemetry: "https://localhost:1/telemetry"), + Endpoints: new CopilotUserEndpoints(Api: context.ProxyUrl, Telemetry: context.ProxyUrl), AnalyticsTrackingId: "e2e-test-tracking-id", Id: 12345)); return context; @@ -302,6 +303,10 @@ public Dictionary GetEnvironment() // disables the method (runtime filters out empty HMAC keys). env["COPILOT_HMAC_KEY"] = ""; env["CAPI_HMAC_KEY"] = ""; + if (DiagnosticsEnabled) + { + env["RUST_LOG"] = "error,sdk_diagnostics=debug"; + } return env!; } @@ -322,6 +327,10 @@ public CopilotClient CreateClient( options ??= new CopilotClientOptions(); options.Logger ??= Logger; + if (DiagnosticsEnabled) + { + options.LogLevel = CopilotLogLevel.Debug; + } // Resolve the working directory the worker should run in. Child-process and // URI transports take it as a per-client option; the in-process transport diff --git a/dotnet/test/Harness/E2ETestFixture.cs b/dotnet/test/Harness/E2ETestFixture.cs index 9bc0efcf71..b66476670f 100644 --- a/dotnet/test/Harness/E2ETestFixture.cs +++ b/dotnet/test/Harness/E2ETestFixture.cs @@ -12,15 +12,15 @@ public class E2ETestFixture : IAsyncLifetime internal const string SharedTcpConnectionToken = "e2e-shared-token"; public E2ETestContext Ctx { get; private set; } = null!; - public CopilotClient Client { get; private set; } = null!; + private CopilotClient? _client; + public CopilotClient Client => _client ??= Ctx.CreateClient(options: new CopilotClientOptions + { + Connection = CreateSharedConnection(E2ETestContext.UsesInProcessTransport), + }, persistent: true); public async Task InitializeAsync() { Ctx = await E2ETestContext.CreateAsync(); - Client = Ctx.CreateClient(options: new CopilotClientOptions - { - Connection = CreateSharedConnection(E2ETestContext.UsesInProcessTransport), - }, persistent: true); } internal static RuntimeConnection CreateSharedConnection(bool useInProcessTransport) => diff --git a/dotnet/test/Harness/ReplayProxy.cs b/dotnet/test/Harness/ReplayProxy.cs index 140642a2f7..6891aeae71 100644 --- a/dotnet/test/Harness/ReplayProxy.cs +++ b/dotnet/test/Harness/ReplayProxy.cs @@ -32,7 +32,7 @@ async Task StartCoreAsync() { FileName = "node", WorkingDirectory = Path.Join(FindRepoRoot(), "test", "harness"), - Arguments = "--import tsx server.ts", + Arguments = "startup.mjs", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -89,7 +89,10 @@ async Task StartCoreAsync() { if (e.Data == null) return; diagnostics.AppendError(e.Data); - Console.Error.WriteLine(e.Data); + if (!e.Data.StartsWith("[SDK proxy startup]", StringComparison.Ordinal)) + { + Console.Error.WriteLine(e.Data); + } }; try diff --git a/dotnet/test/Unit/AutoTierIdentityTests.cs b/dotnet/test/Unit/AutoTierIdentityTests.cs new file mode 100644 index 0000000000..9ca10e346d --- /dev/null +++ b/dotnet/test/Unit/AutoTierIdentityTests.cs @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +using System.Text.Json; +using System.Text.Json.Serialization.Metadata; +using GitHub.Copilot.Rpc; +using Xunit; + +#pragma warning disable GHCP001 // Exercise the public model RPC projection. + +namespace GitHub.Copilot.Test.Unit; + +public class AutoTierIdentityTests +{ + private static readonly JsonSerializerOptions JsonOptions = new() + { + TypeInfoResolver = new DefaultJsonTypeInfoResolver(), + }; + + [Fact] + public void CaseDistinctTierIdsRemainDistinctAcrossCollectionsAndJson() + { + var custom = new AutoTier("BALANCE"); + Assert.NotEqual(AutoTier.Balance, custom); + Assert.Equal(2, new HashSet { AutoTier.Balance, custom }.Count); + Assert.Equal("\"BALANCE\"", JsonSerializer.Serialize(custom, JsonOptions)); + Assert.Equal(custom, JsonSerializer.Deserialize("\"BALANCE\"", JsonOptions)); + Assert.Equal("balance", AutoTier.Balance.Value); + + var rpc = JsonSerializer.Deserialize("""{"modelId":"auto","autoTier":"BALANCE"}""", JsonOptions); + Assert.NotNull(rpc); + Assert.Equal(custom, rpc.AutoTier); + Assert.NotEqual(AutoTier.Balance, rpc.AutoTier); + } + + [Fact] + public void CaseDistinctRecommendationIdsRemainDistinct() + { + var custom = new RecommendedAutoTier("BALANCE"); + Assert.NotEqual(RecommendedAutoTier.Balance, custom); + Assert.Equal(2, new HashSet { RecommendedAutoTier.Balance, custom }.Count); + Assert.Equal("\"BALANCE\"", JsonSerializer.Serialize(custom, JsonOptions)); + Assert.Equal(custom, JsonSerializer.Deserialize("\"BALANCE\"", JsonOptions)); + } +} diff --git a/dotnet/test/Unit/ClientSessionLifetimeTests.AhpHost.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.AhpHost.cs index f0b584af7b..9fdea1bc92 100644 --- a/dotnet/test/Unit/ClientSessionLifetimeTests.AhpHost.cs +++ b/dotnet/test/Unit/ClientSessionLifetimeTests.AhpHost.cs @@ -74,7 +74,7 @@ public async Task Ahp_Snapshots_Transport_Settings_Before_Connecting() } }; var local = new HostLocalServerOptions { Hostname = "127.0.0.1", Port = 0, Token = "original", RequireConnectionToken = true }; - var github = new HostGitHubEnvironmentOptions { Name = "original", ComputeId = "compute" }; + var github = new HostGitHubEnvironmentOptions { Name = "original", ComputeId = "compute", RequireConnectionBinding = false }; var pending = client.StartAhpHostAsync(new() { LocalServer = local, GitHubEnvironment = github }); await connecting.Task.WaitAsync(TimeSpan.FromSeconds(10)); try @@ -85,6 +85,7 @@ public async Task Ahp_Snapshots_Transport_Settings_Before_Connecting() local.RequireConnectionToken = false; github.Name = ""; github.ComputeId = ""; + github.RequireConnectionBinding = true; } finally { @@ -100,6 +101,7 @@ public async Task Ahp_Snapshots_Transport_Settings_Before_Connecting() var githubSettings = request.GetProperty("githubEnvironment"); Assert.Equal("original", githubSettings.GetProperty("name").GetString()); Assert.Equal("compute", githubSettings.GetProperty("computeId").GetString()); + Assert.False(githubSettings.GetProperty("requireConnectionBinding").GetBoolean()); } [Theory] @@ -112,10 +114,12 @@ public async Task Ahp_Forwards_Explicit_Transports_And_Optional_Readiness(bool l await using var client = new CopilotClient(new() { Connection = RuntimeConnection.ForUri(server.Url) }); await using var host = await client.StartAhpHostAsync(new() { + ComputeId = "compute", LocalServer = local ? new() { Hostname = "127.0.0.1", Port = 0, Token = "test-token", RequireConnectionToken = true } : null, GitHubEnvironment = github ? new() { Name = "test host", ComputeId = "compute" } : null }); var request = Assert.Single(server.Requests, request => request.Method == "host.start").Params; + Assert.Equal("compute", request.GetProperty("computeId").GetString()); Assert.Equal(local, request.TryGetProperty("localServer", out var localSettings) && localSettings.ValueKind == JsonValueKind.Object); Assert.Equal(github, request.TryGetProperty("githubEnvironment", out var githubSettings) && githubSettings.ValueKind == JsonValueKind.Object); foreach (var oldField in new[] { "hostname", "port", "token", "requireConnectionToken" }) @@ -136,6 +140,60 @@ public async Task Ahp_Forwards_Explicit_Transports_And_Optional_Readiness(bool l Assert.Null(host.Pid); } + [Fact] + public async Task Ahp_Legacy_Positional_Start_And_Additive_Request_Overloads() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new() { Connection = RuntimeConnection.ForUri(server.Url) }); + await client.StartAsync(); + var local = new HostLocalServerOptions { Port = 12345 }; + var github = new HostGitHubEnvironmentOptions { Name = "host", ComputeId = "compute" }; + + await client.Rpc.Host.StartAsync("legacy", local, github, true, false, CancellationToken.None); + await client.Rpc.Host.StartAsync("defaults"); + await client.Rpc.Host.StartAsync(new HostStartRequest + { + HostId = "request", + ComputeId = "compute", + LocalServer = local, + GitHubEnvironment = github, + SessionFactory = true, + ResumeFactory = false + }, CancellationToken.None); + + var requests = server.Requests.Where(request => request.Method == "host.start").ToArray(); + Assert.Equal(3, requests.Length); + var legacy = requests[0].Params; + Assert.Equal("legacy", legacy.GetProperty("hostId").GetString()); + Assert.False(legacy.TryGetProperty("computeId", out _)); + Assert.Equal("defaults", requests[1].Params.GetProperty("hostId").GetString()); + Assert.False(requests[1].Params.TryGetProperty("localServer", out _)); + var additive = requests[2].Params; + Assert.Equal("request", additive.GetProperty("hostId").GetString()); + Assert.Equal("compute", additive.GetProperty("computeId").GetString()); + foreach (var parameters in new[] { legacy, additive }) + { + Assert.Equal(12345, parameters.GetProperty("localServer").GetProperty("port").GetInt32()); + Assert.Equal("compute", parameters.GetProperty("githubEnvironment").GetProperty("computeId").GetString()); + Assert.True(parameters.GetProperty("sessionFactory").GetBoolean()); + Assert.False(parameters.GetProperty("resumeFactory").GetBoolean()); + } + } + + [Fact] + public async Task Ahp_List_Sessions_Uses_Owning_Host() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new() { Connection = RuntimeConnection.ForUri(server.Url) }); + await using var host = await client.StartAhpHostAsync(new() { LocalServer = new() }); + + var result = await host.ListSessionsAsync(); + + Assert.Empty(result.Sessions); + var request = Assert.Single(server.Requests, request => request.Method == "host.listSessions").Params; + Assert.Equal(host.HostId, request.GetProperty("hostId").GetString()); + } + [Theory] [InlineData(true)] [InlineData(false)] diff --git a/dotnet/test/Unit/ClientSessionLifetimeTests.CustomizationDirectories.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.CustomizationDirectories.cs new file mode 100644 index 0000000000..7e7aee511f --- /dev/null +++ b/dotnet/test/Unit/ClientSessionLifetimeTests.CustomizationDirectories.cs @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +#if NET8_0_OR_GREATER +using GitHub.Copilot.Rpc; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed partial class ClientSessionLifetimeTests +{ + [Fact] + public async Task CustomizationDirectories_Preserve_Positional_Discovery_Calls() + { + await using var server = await FakeCopilotServer.StartAsync(); + server.ResponseFactory = _ => new Dictionary + { + ["agents"] = Array.Empty(), + ["hooks"] = Array.Empty(), + ["sources"] = Array.Empty(), + ["paths"] = Array.Empty() + }; + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + IList projects = ["project-root"]; + await client.StartAsync(); + await client.Rpc.Agents.DiscoverAsync(projects, true, CancellationToken.None); + await client.Rpc.Agents.GetDiscoveryPathsAsync(projects, true, CancellationToken.None); + await client.Rpc.Hooks.DiscoverAsync(projects, true, CancellationToken.None); + await client.Rpc.Instructions.DiscoverAsync(projects, true, CancellationToken.None); + await client.Rpc.Instructions.GetDiscoveryPathsAsync(projects, true, CancellationToken.None); + await client.Rpc.Skills.GetDiscoveryPathsAsync(projects, ["ignored"], true, CancellationToken.None); + foreach (var method in new[] + { + "agents.discover", "agents.getDiscoveryPaths", "hooks.discover", + "instructions.discover", "instructions.getDiscoveryPaths", "skills.getDiscoveryPaths" + }) + { + var payload = Assert.Single(server.Requests, request => request.Method == method).Params; + Assert.Equal("project-root", Assert.Single(payload.GetProperty("projectPaths").EnumerateArray()).GetString()); + foreach (var key in new[] { "agentDirectories", "hookDirectories", "instructionDirectories", "skillDirectories" }) + { + Assert.False(payload.TryGetProperty(key, out _)); + } + } + await client.Rpc.Agents.DiscoverAsync(new AgentsDiscoverRequest + { + AgentDirectories = ["explicit-agent-root"] + }); + var explicitPayload = server.Requests.Last(request => request.Method == "agents.discover").Params; + Assert.Equal("explicit-agent-root", Assert.Single(explicitPayload.GetProperty("agentDirectories").EnumerateArray()).GetString()); + Assert.False(explicitPayload.TryGetProperty("projectPaths", out _)); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public async Task CustomizationDirectories_Are_Preserved_On_Create_And_Resume(int kind) + { + IList? roots = kind switch + { + 0 => null, + 1 => [], + _ => ["relative-root", "other-root"] + }; + var directories = new Dictionary?> + { + ["skillDirectories"] = roots?.Select(root => root + "-skills").ToList(), + ["agentDirectories"] = roots?.Select(root => root + "-agents").ToList(), + ["instructionDirectories"] = roots?.Select(root => root + "-instructions").ToList(), + ["hookDirectories"] = roots?.Select(root => root + "-hooks").ToList() + }; + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + await using var created = await client.CreateSessionAsync(new SessionConfig + { + WorkingDirectory = "request-cwd", + EnableConfigDiscovery = false, + EnableFileHooks = false, + SkillDirectories = directories["skillDirectories"], + AgentDirectories = directories["agentDirectories"], + InstructionDirectories = directories["instructionDirectories"], + HookDirectories = directories["hookDirectories"] + }); + await using var resumed = await client.ResumeSessionAsync("resumed", new ResumeSessionConfig + { + WorkingDirectory = "resume-cwd", + EnableConfigDiscovery = false, + EnableFileHooks = false, + SkillDirectories = directories["skillDirectories"], + AgentDirectories = directories["agentDirectories"], + InstructionDirectories = directories["instructionDirectories"], + HookDirectories = directories["hookDirectories"] + }); + foreach (var method in new[] { "session.create", "session.resume" }) + { + var payload = Assert.Single(server.Requests, request => request.Method == method).Params; + foreach (var entry in directories) + { + if (entry.Value is null) + { + Assert.False(payload.TryGetProperty(entry.Key, out _)); + } + else + { + Assert.Equal(entry.Value, payload.GetProperty(entry.Key).EnumerateArray().Select(item => item.GetString())); + } + } + Assert.False(payload.GetProperty("enableConfigDiscovery").GetBoolean()); + Assert.False(payload.GetProperty("enableFileHooks").GetBoolean()); + Assert.False(payload.TryGetProperty("additionalDirectories", out _)); + Assert.False(payload.TryGetProperty("customAgents", out _)); + Assert.False(payload.TryGetProperty("hooks", out _)); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void CustomizationDirectories_Clone_Owns_Its_Lists(bool resume) + { + SessionConfigBase original; + SessionConfigBase clone; + if (resume) + { + var config = new ResumeSessionConfig + { + AgentDirectories = ["agents"], + HookDirectories = ["hooks"] + }; + original = config; + clone = config.Clone(); + } + else + { + var config = new SessionConfig + { + AgentDirectories = ["agents"], + HookDirectories = ["hooks"] + }; + original = config; + clone = config.Clone(); + } + clone.AgentDirectories!.Add("clone-agents"); + clone.HookDirectories!.Add("clone-hooks"); + Assert.Equal("agents", Assert.Single(original.AgentDirectories!)); + Assert.Equal("hooks", Assert.Single(original.HookDirectories!)); + Assert.Collection(clone.AgentDirectories, item => Assert.Equal("agents", item), item => Assert.Equal("clone-agents", item)); + Assert.Collection(clone.HookDirectories, item => Assert.Equal("hooks", item), item => Assert.Equal("clone-hooks", item)); + } +} +#endif diff --git a/dotnet/test/Unit/ClientSessionLifetimeTests.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.cs index d78ee57932..c3ea694395 100644 --- a/dotnet/test/Unit/ClientSessionLifetimeTests.cs +++ b/dotnet/test/Unit/ClientSessionLifetimeTests.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Text; using System.Text.Json; using GitHub.Copilot.Rpc; @@ -23,6 +24,40 @@ public sealed partial class ClientSessionLifetimeTests { private sealed record RpcRequestRecord(string Method, JsonElement Params); + [Theory] + [InlineData(false, true)] + [InlineData(false, false)] + [InlineData(false, null)] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(true, null)] + public async Task ImageGeneration_ForwardsCreateAndResumeOptIn(bool resume, bool? enabled) + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var imageGeneration = enabled is null ? null : new ImageGenerationConfig { Enabled = enabled }; + await using var session = resume + ? await client.ResumeSessionAsync("image-test", new ResumeSessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + ImageGeneration = imageGeneration + }.Clone()) + : await client.CreateSessionAsync(new SessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + ImageGeneration = imageGeneration + }.Clone()); + var request = Assert.Single(server.Requests, r => r.Method == (resume ? "session.resume" : "session.create")).Params; + if (enabled is null) + { + Assert.False(request.TryGetProperty("imageGeneration", out _), request.ToString()); + } + else + { + Assert.Equal(enabled.Value, request.GetProperty("imageGeneration").GetProperty("enabled").GetBoolean()); + } + } + [Theory] [InlineData(CopilotClientMode.CopilotCli, null, null)] [InlineData(CopilotClientMode.Empty, null, null)] @@ -1791,6 +1826,613 @@ async Task BlockedTool(CancellationToken cancellationToken) } } + [Fact] + public Task ForceStopAsync_Does_Not_Invoke_Remaining_Event_Handlers() => + AssertRemainingEventHandlersStoppedAsync(static (client, _, _) => client.ForceStopAsync()); + + [Fact] + public Task DisposeAsync_Does_Not_Invoke_Remaining_Event_Handlers() => + AssertRemainingEventHandlersStoppedAsync(static (_, session, _) => session.DisposeAsync().AsTask()); + + [Fact] + public Task Unsubscribe_Releases_Unadmitted_Event_Handler_Captures() => + AssertRemainingEventHandlersStoppedAsync(static (_, _, unsubscribe) => + { + unsubscribe(); + return Task.CompletedTask; + }); + + [Fact] + public Task ForceStopAsync_Fails_Pending_SendAndWait_After_Send_Response() => + AssertPendingSendAndWaitStoppedAsync(static (client, _) => client.ForceStopAsync()); + + [Fact] + public Task DisposeAsync_Fails_Pending_SendAndWait_After_Send_Response() => + AssertPendingSendAndWaitStoppedAsync(static (_, session) => session.DisposeAsync().AsTask()); + + [Fact] + public async Task ForceStopAsync_Rejects_Event_Handler_Registration() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + + await client.ForceStopAsync(); + + Assert.Throws(() => session.On(_ => { })); + } + + [Theory] + [InlineData(false, true)] + [InlineData(true, true)] + [InlineData(false, false)] + [InlineData(true, false)] + public async Task Stop_Rejects_And_Retires_Session_Initialized_Before_Registration(bool resume, bool force) + { + await using var server = await FakeCopilotServer.StartAsync(); + server.ResponseFactory = request => request.Method == "sessionFs.setProvider" + ? new Dictionary { ["success"] = true } + : throw new InvalidOperationException($"Unexpected RPC method '{request.Method}'."); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url), + SessionFs = new SessionFsConfig + { + InitialWorkingDirectory = "/", + SessionStatePath = "/session-state", + Conventions = SessionFsSetProviderConventions.Posix + } + }); + await client.StartAsync(); + using var releaseSetup = new ManualResetEventSlim(); + var setupStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + SessionFsProvider CreateProvider(CopilotSession session) + { + setupStarted.SetResult(session); + releaseSetup.Wait(); + return new TextOnlySessionFsProvider(); + } + var creation = Task.Run(() => resume + ? client.ResumeSessionAsync("late-registration", new ResumeSessionConfig { CreateSessionFsProvider = CreateProvider }) + : client.CreateSessionAsync(new SessionConfig { CreateSessionFsProvider = CreateProvider })); + try + { + var session = await setupStarted.Task.WaitAsync(TimeSpan.FromSeconds(5)); + if (force) + { + await client.ForceStopAsync().WaitAsync(TimeSpan.FromSeconds(5)); + } + else + { + await client.StopAsync().WaitAsync(TimeSpan.FromSeconds(5)); + } + releaseSetup.Set(); + var error = await Assert.ThrowsAsync(() => creation.WaitAsync(TimeSpan.FromSeconds(5))); + Assert.Contains("stopped connection", error.Message); + Assert.Throws(() => session.On(_ => { })); + Assert.DoesNotContain(server.Requests, request => request.Method is "session.create" or "session.resume"); + } + finally + { + releaseSetup.Set(); + await Record.ExceptionAsync(() => creation.WaitAsync(TimeSpan.FromSeconds(5))); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task Stop_Closes_Session_Admission_Before_Transport_Cleanup(bool resume) + { + await using var server = await FakeCopilotServer.StartAsync(); + server.ResponseFactory = request => request.Method == "sessionFs.setProvider" + ? new Dictionary { ["success"] = true } + : throw new InvalidOperationException($"Unexpected RPC method '{request.Method}'."); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url), + SessionFs = new SessionFsConfig + { + InitialWorkingDirectory = "/", + SessionStatePath = "/session-state", + Conventions = SessionFsSetProviderConventions.Posix + } + }); + _ = await client.CreateSessionAsync(new SessionConfig { CreateSessionFsProvider = _ => new TextOnlySessionFsProvider() }); + server.DelayDestroy(); + var stop = client.StopAsync(); + await server.DestroyStarted.WaitAsync(TimeSpan.FromSeconds(5)); + try + { + CopilotSession? initialized = null; + SessionFsProvider CreateProvider(CopilotSession session) + { + initialized = session; + return new TextOnlySessionFsProvider(); + } + var creation = resume + ? client.ResumeSessionAsync("late-registration", new ResumeSessionConfig { CreateSessionFsProvider = CreateProvider }) + : client.CreateSessionAsync(new SessionConfig { CreateSessionFsProvider = CreateProvider }); + var error = await Assert.ThrowsAsync(() => creation.WaitAsync(TimeSpan.FromSeconds(5))); + Assert.Contains("stopped connection", error.Message); + Assert.NotNull(initialized); + Assert.Throws(() => initialized.On(_ => { })); + Assert.False(stop.IsCompleted); + } + finally + { + await client.ForceStopAsync().WaitAsync(TimeSpan.FromSeconds(5)); + await stop.WaitAsync(TimeSpan.FromSeconds(5)); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task Cloud_Create_Cleanup_Does_Not_Reconnect_During_Stop(bool dispose) + { + await using var server = await FakeCopilotServer.StartAsync(); + server.ResponseFactory = request => request.Method == "sessionFs.setProvider" + ? new Dictionary { ["success"] = true } + : throw new InvalidOperationException($"Unexpected RPC method '{request.Method}'."); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url), + SessionFs = new SessionFsConfig + { + InitialWorkingDirectory = "/", + SessionStatePath = "/session-state", + Conventions = SessionFsSetProviderConventions.Posix + } + }); + await client.StartAsync(); + using var process = StartExitedProcess(); + await ReplaceConnectionResourcesAsync(client, process); + using var releaseSetup = new ManualResetEventSlim(); + using var reconnectCancellation = new CancellationTokenSource(); + var reconnect = server.ObserveReconnectAsync(reconnectCancellation.Token); + var setupStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var shutdownStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var releaseShutdown = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + server.BeforeResponseAsync = async (request, token) => + { + if (request.Method == "runtime.shutdown") + { + shutdownStarted.TrySetResult(); + await releaseShutdown.Task.WaitAsync(token); + } + }; + var creation = client.CreateSessionAsync(new SessionConfig + { + Cloud = new CloudSessionOptions + { + Repository = new CloudSessionRepository { Owner = "github", Name = "copilot-sdk", Branch = "main" } + }, + CreateSessionFsProvider = session => + { + setupStarted.TrySetResult(session); + releaseSetup.Wait(); + return new TextOnlySessionFsProvider(); + } + }); + Task? stop = null; + Exception? failure = null; + var timeout = TimeSpan.FromSeconds(5); + try + { + var session = await setupStarted.Task.WaitAsync(timeout); + stop = dispose ? client.DisposeAsync().AsTask() : client.StopAsync(); + await shutdownStarted.Task.WaitAsync(timeout); + releaseSetup.Set(); + releaseShutdown.TrySetResult(); + + var error = await Assert.ThrowsAsync(() => creation.WaitAsync(timeout)); + Assert.Contains("stopped connection", error.Message); + await stop.WaitAsync(timeout); + Assert.Throws(() => session.On(_ => { })); + Assert.False(server.ReconnectObserved, "Cloud-create cleanup reconnected after session admission closed."); + } + catch (Exception error) + { + failure = error; + } + finally + { + releaseSetup.Set(); + releaseShutdown.TrySetResult(); + foreach (var operation in new Task?[] { creation, stop }) + { + if (operation is null) continue; + try + { + await operation.WaitAsync(timeout); + } + catch (IOException) when (ReferenceEquals(operation, creation)) + { + // The rejected creation is the expected result, not a cleanup failure. + } + catch (Exception cleanupError) + { + failure = failure is null ? cleanupError : new AggregateException(failure, cleanupError); + } + } + reconnectCancellation.Cancel(); + try + { + await reconnect.WaitAsync(timeout); + } + catch (OperationCanceledException) when (reconnectCancellation.IsCancellationRequested) + { + } + catch (Exception cleanupError) + { + failure = failure is null ? cleanupError : new AggregateException(failure, cleanupError); + } + } + if (failure is not null) + { + ExceptionDispatchInfo.Capture(failure).Throw(); + } + } + + [Theory] + [InlineData("hooks", true)] + [InlineData("mcp", true)] + [InlineData("bearer", true)] + [InlineData("transforms", true)] + [InlineData("tools", true)] + [InlineData("commands", true)] + [InlineData("permission", true)] + [InlineData("input", true)] + [InlineData("hooks", false)] + [InlineData("mcp", false)] + [InlineData("bearer", false)] + [InlineData("transforms", false)] + [InlineData("tools", false)] + [InlineData("commands", false)] + [InlineData("permission", false)] + [InlineData("input", false)] + public async Task Retirement_Releases_Retained_Session_Callback_Captures(string registration, bool forceStop) + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var (session, capture) = await CreateCapturedSessionAsync(client, registration); + await using var retainedSession = session; + ForceCollect(); + Assert.True(CaptureIsAlive(capture)); + + if (forceStop) + { + await client.ForceStopAsync(); + } + else + { + await session.DisposeAsync(); + } + ForceCollect(); + + Assert.False(CaptureIsAlive(capture)); + GC.KeepAlive(session); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool CaptureIsAlive(WeakReference capture) => capture.TryGetTarget(out _); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static async Task<(CopilotSession Session, WeakReference Capture)> CreateCapturedSessionAsync( + CopilotClient client, string registration) + { + var capture = new object(); + var weak = new WeakReference(capture); + var config = new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll }; + switch (registration) + { + case "hooks": + config.Hooks = new SessionHooks + { + OnSessionStart = (_, _) => + { + GC.KeepAlive(capture); + return Task.FromResult(null); + } + }; + break; + case "mcp": + config.OnMcpAuthRequest = _ => + { + GC.KeepAlive(capture); + return Task.FromResult(McpAuthResult.Cancel()); + }; + break; + case "bearer": + config.Model = "test-model"; + config.Provider = new ProviderConfig + { + BaseUrl = "http://127.0.0.1", + BearerTokenProvider = _ => + { + GC.KeepAlive(capture); + return Task.FromResult("test-token"); + } + }; + break; + case "transforms": + config.SystemMessage = new SystemMessageConfig + { + Mode = SystemMessageMode.Customize, + Sections = new Dictionary + { + [SystemMessageSection.Tone] = new() + { + Transform = content => + { + GC.KeepAlive(capture); + return Task.FromResult(content); + } + } + } + }; + break; + case "tools": + config.Tools = [AIFunctionFactory.Create(() => + { + GC.KeepAlive(capture); + return "test-result"; + }, "captured_tool")]; + break; + case "commands": + config.Commands = [new CommandDefinition + { + Name = "captured", + Handler = _ => + { + GC.KeepAlive(capture); + return Task.CompletedTask; + } + }]; + break; + case "permission": + config.OnPermissionRequest = (_, _) => + { + GC.KeepAlive(capture); + return Task.FromResult(PermissionDecision.UserNotAvailable()); + }; + break; + case "input": + config.OnUserInputRequest = (_, _) => + { + GC.KeepAlive(capture); + return Task.FromResult(new UserInputResponse { Answer = "test-answer" }); + }; + break; + default: + throw new ArgumentOutOfRangeException(nameof(registration), registration, "Unknown callback registration."); + } + return (await client.CreateSessionAsync(config), weak); + } + + [Fact] + public async Task DisposeAsync_Keeps_Hooks_Through_Detach_Acknowledgement() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var detachStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var releaseDetach = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var hookStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var hooks = new SessionHooks + { + OnSessionEnd = (_, _) => + { + hookStarted.TrySetResult(); + return Task.FromResult(null); + } + }; + var endHook = hooks.OnSessionEnd; + await using var session = await client.CreateSessionAsync(new SessionConfig { Hooks = hooks }); + server.BeforeResponseAsync = async (request, token) => + { + if (request.Method == "session.detach") + { + detachStarted.TrySetResult(); + await releaseDetach.Task.WaitAsync(token); + } + }; + var timeout = TimeSpan.FromSeconds(5); + var disposal = session.DisposeAsync().AsTask(); + Task? hookRequest = null; + Exception? bodyFailure = null; + try + { + await detachStarted.Task.WaitAsync(timeout); + hookRequest = server.SendRequestAsync("hooks.invoke", new Dictionary + { + ["sessionId"] = session.SessionId, + ["hookType"] = "sessionEnd", + ["input"] = new Dictionary + { + ["sessionId"] = session.SessionId, + ["timestamp"] = 1_730_000_000_000L, + ["cwd"] = "workdir", + ["reason"] = "complete" + } + }); + await hookStarted.Task.WaitAsync(timeout); + } + catch (Exception error) + { + bodyFailure = error; + } + finally + { + releaseDetach.TrySetResult(); + foreach (var operation in new Task?[] { disposal, hookRequest }) + { + if (operation is null) continue; + try + { + await operation.WaitAsync(timeout); + } + catch (Exception cleanupError) + { + bodyFailure = bodyFailure is null ? cleanupError : new AggregateException(bodyFailure, cleanupError); + } + } + } + if (bodyFailure is not null) + { + ExceptionDispatchInfo.Capture(bodyFailure).Throw(); + } + Assert.Same(endHook, hooks.OnSessionEnd); + } + + [Fact] + public async Task DisposeAsync_Releases_Event_Handler_Captures() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + var capture = RegisterCapturedEventHandler(session, out _); + + await session.DisposeAsync(); + ForceCollect(); + + Assert.False(capture.TryGetTarget(out _)); + GC.KeepAlive(session); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static WeakReference RegisterCapturedEventHandler(CopilotSession session, out IDisposable subscription) + { + var capture = new object(); + subscription = session.On(_ => GC.KeepAlive(capture)); + return new WeakReference(capture); + } + + private static async Task AssertPendingSendAndWaitStoppedAsync(Func stop) + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + using var cancellation = new CancellationTokenSource(); + var timeout = TimeSpan.FromSeconds(5); + var responseDrained = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + server.AfterResponseAsync = async (request, token) => + { + if (request.Method == "session.send") + { + await server.SendAndDrainSessionEventAsync(session, "assistant.message", new() + { + ["messageId"] = "message-1", + ["content"] = "WAITING_FOR_IDLE" + }, timeout, token); + responseDrained.TrySetResult(); + } + }; + var pending = session.SendAndWaitAsync(new MessageOptions { Prompt = "wait until idle" }, cancellationToken: cancellation.Token); + Exception? bodyFailure = null; + try + { + await responseDrained.Task.WaitAsync(timeout); + await stop(client, session).WaitAsync(timeout); + await Assert.ThrowsAsync(() => pending.WaitAsync(timeout)); + } + catch (Exception error) + { + bodyFailure = error; + } + finally + { + try + { + cancellation.Cancel(); + await pending.WaitAsync(timeout); + } + catch (Exception error) when (error is IOException or OperationCanceledException) + { + // The stopped operation may fault, or the owned cleanup cancellation may end it. + } + catch (Exception cleanupError) + { + bodyFailure = bodyFailure is null ? cleanupError : new AggregateException(bodyFailure, cleanupError); + } + } + if (bodyFailure is not null) + { + ExceptionDispatchInfo.Capture(bodyFailure).Throw(); + } + } + + private static async Task AssertRemainingEventHandlersStoppedAsync(Func stop) + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + // Channel closure may queue a final continuation after disposal; an idle pair owns no thread. + var scheduler = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, maxConcurrencyLevel: 1); + var factory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler.ExclusiveScheduler); + using var releaseHandler = new ManualResetEventSlim(); + var handlerStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var laterHandlerCalls = 0; + CopilotSession? session = null; + Exception? bodyFailure = null; + try + { + // Resume starts the event consumer on the caller's scheduler. A queued task fences + // that consumer's current dispatch without relying on a delay or private SDK state. + session = await factory.StartNew(() => client.ResumeSessionAsync("force-stop-event-handler", new ResumeSessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll + })).Unwrap(); + using var first = session.On(_ => + { + handlerStarted.TrySetResult(TaskScheduler.Current); + releaseHandler.Wait(); + }); + using var second = session.On(_ => Interlocked.Increment(ref laterHandlerCalls)); + var capture = RegisterCapturedEventHandler(session, out var capturedSubscription); + using var captureSubscription = capturedSubscription; + await server.SendSessionEventAsync(session.SessionId, "assistant.message", new() + { + ["messageId"] = "force-stop-dispatch", + ["content"] = "STOP_EVENT_DISPATCH" + }); + Assert.Same(scheduler.ExclusiveScheduler, await handlerStarted.Task.WaitAsync(TimeSpan.FromSeconds(5))); + await stop(client, session, () => + { + second.Dispose(); + captureSubscription.Dispose(); + }).WaitAsync(TimeSpan.FromSeconds(5)); + ForceCollect(); + Assert.False(capture.TryGetTarget(out _)); + releaseHandler.Set(); + await factory.StartNew(() => { }).WaitAsync(TimeSpan.FromSeconds(5)); + Assert.Equal(0, Volatile.Read(ref laterHandlerCalls)); + } + catch (Exception error) + { + bodyFailure = error; + } + finally + { + releaseHandler.Set(); + try + { + await factory.StartNew(() => { }).WaitAsync(TimeSpan.FromSeconds(5)); + if (session is not null) + { + await session.DisposeAsync(); + } + } + catch (Exception cleanupError) + { + bodyFailure = bodyFailure is null ? cleanupError : new AggregateException(bodyFailure, cleanupError); + } + } + if (bodyFailure is not null) + { + ExceptionDispatchInfo.Capture(bodyFailure).Throw(); + } + } + [Fact] public async Task ForceStopAsync_Does_Not_Start_Late_External_Tool() { @@ -1888,6 +2530,86 @@ async Task BlockedTool(CancellationToken cancellationToken) } } + [Fact] + public async Task ExternalTool_Invocation_Names_The_Sub_Agent_And_Request_Behind_The_Call() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var invocations = new ConcurrentQueue(); + var tool = CopilotTool.DefineTool( + (ToolInvocation invocation) => + { + invocations.Enqueue(invocation); + return "ok"; + }, + factoryOptions: new AIFunctionFactoryOptions { Name = "calc" }); + await using var session = await client.CreateSessionAsync(new SessionConfig + { + Tools = [tool], + OnPermissionRequest = PermissionHandler.ApproveAll + }); + server.ClearRequests(); + + DispatchEvent(session, new ExternalToolRequestedEvent + { + AgentId = "task-agent-1", + Data = new ExternalToolRequestedData + { + RequestId = "req-sub-agent", + SessionId = session.SessionId, + ToolCallId = "tc-sub-agent", + ToolName = "calc" + } + }); + await WaitForRequestAsync(server, "session.tools.handlePendingToolCall"); + server.ClearRequests(); + DispatchEvent(session, new ExternalToolRequestedEvent + { + Data = new ExternalToolRequestedData + { + RequestId = "req-root", + SessionId = session.SessionId, + ToolCallId = "tc-root", + ToolName = "calc" + } + }); + await WaitForRequestAsync(server, "session.tools.handlePendingToolCall"); + server.ClearRequests(); + DispatchEvent(session, new ExternalToolRequestedEvent + { + AgentId = "", + Data = new ExternalToolRequestedData + { + RequestId = "req-blank-agent", + SessionId = session.SessionId, + ToolCallId = "tc-blank-agent", + ToolName = "calc" + } + }); + await WaitForRequestAsync(server, "session.tools.handlePendingToolCall"); + + Assert.Collection( + invocations, + subAgentCall => + { + Assert.Equal("tc-sub-agent", subAgentCall.ToolCallId); + Assert.Equal("task-agent-1", subAgentCall.AgentId); + Assert.Equal("req-sub-agent", subAgentCall.RequestId); + }, + rootCall => + { + Assert.Equal("tc-root", rootCall.ToolCallId); + Assert.Null(rootCall.AgentId); + Assert.Equal("req-root", rootCall.RequestId); + }, + blankAgentCall => + { + Assert.Equal("tc-blank-agent", blankAgentCall.ToolCallId); + Assert.Null(blankAgentCall.AgentId); + Assert.Equal("req-blank-agent", blankAgentCall.RequestId); + }); + } + private static ExternalToolRequestedEvent ExternalToolRequested(string requestId, string toolName = "blocked_tool") => new() { @@ -2503,7 +3225,8 @@ public async Task SendAndWaitAsync_Waits_For_Earlier_Idle_Handler() using var subscription = session.On(_ => { entered.TrySetResult(); - handlerFinished = release.Wait(TimeSpan.FromSeconds(5)); + release.Wait(); + handlerFinished = true; }); var pending = session.SendAndWaitAsync(new MessageOptions { Prompt = "hello" }); await WaitForRequestAsync(server, "session.send"); @@ -2606,14 +3329,17 @@ public async Task CreateSessionAsync_Serializes_ManagedSettings_Permissions() await using var session = await client.CreateSessionAsync(new SessionConfig { + EnforceManagedModelDefaults = true, ManagedSettings = new ManagedSettings { Permissions = new ManagedSettingsPermissions { DisableBypassPermissionsMode = DisableBypassPermissionsModes.Disable, + DisableAssistedPermissionsMode = true, Deny = ["shell(rm*)"], Ask = ["write"], - Allow = [] + Allow = [], + LimitTo = ["Domain(github.com)"] } }, OnPermissionRequest = (_, invocation) => @@ -2624,12 +3350,17 @@ public async Task CreateSessionAsync_Serializes_ManagedSettings_Permissions() }); var request = Assert.Single(server.Requests, request => request.Method == "session.create"); + Assert.True(request.Params.GetProperty("enforceManagedModelDefaults").GetBoolean()); Assert.False(request.Params.TryGetProperty("enableManagedSettings", out _)); var permissions = request.Params.GetProperty("managedSettings").GetProperty("permissions"); Assert.Equal("disable", permissions.GetProperty("disableBypassPermissionsMode").GetString()); + Assert.True(permissions.GetProperty("disableAssistedPermissionsMode").GetBoolean()); Assert.Equal("shell(rm*)", Assert.Single(permissions.GetProperty("deny").EnumerateArray()).GetString()); Assert.Equal("write", Assert.Single(permissions.GetProperty("ask").EnumerateArray()).GetString()); Assert.Empty(permissions.GetProperty("allow").EnumerateArray()); + Assert.Equal( + "Domain(github.com)", + Assert.Single(permissions.GetProperty("limitTo").EnumerateArray()).GetString()); DispatchEvent(session, new PermissionRequestedEvent { @@ -2895,6 +3626,7 @@ public async Task ResumeSessionAsync_Serializes_ManagedSettings_Permissions() await using var session = await client.ResumeSessionAsync("session-managed", new ResumeSessionConfig { + EnforceManagedModelDefaults = true, ManagedSettings = new ManagedSettings { Permissions = new ManagedSettingsPermissions @@ -2907,6 +3639,7 @@ public async Task ResumeSessionAsync_Serializes_ManagedSettings_Permissions() }); var request = Assert.Single(server.Requests, request => request.Method == "session.resume"); + Assert.True(request.Params.GetProperty("enforceManagedModelDefaults").GetBoolean()); var permissions = request.Params.GetProperty("managedSettings").GetProperty("permissions"); Assert.Equal("shell(rm*)", Assert.Single(permissions.GetProperty("deny").EnumerateArray()).GetString()); } @@ -2999,7 +3732,7 @@ private static Process StartExitedProcess() return process; } - private sealed class FakeCopilotServer : IAsyncDisposable + private sealed partial class FakeCopilotServer : IAsyncDisposable { private readonly TcpListener _listener; private readonly CancellationTokenSource _cts = new(); @@ -3018,6 +3751,7 @@ private sealed class FakeCopilotServer : IAsyncDisposable private bool _failRuntimeShutdown; private bool _failSessionCreate; private bool _failSessionSend; + private bool _reconnectObserved; private int _nextMessageId; public bool IncludeTranscriptRecovery { get; set; } @@ -3025,6 +3759,7 @@ private sealed class FakeCopilotServer : IAsyncDisposable public bool UniqueMessageIds { get; set; } public bool FailSessionDelete { get; set; } public bool FailMcpAuthInterestRegistration { get; set; } + public bool ReconnectObserved => Volatile.Read(ref _reconnectObserved); public Func? BeforeSendResponse { get; set; } @@ -3079,6 +3814,12 @@ public void ClearRequests() } } + public async Task ObserveReconnectAsync(CancellationToken cancellationToken) + { + using var connection = await _listener.AcceptTcpClientAsync(cancellationToken); + Volatile.Write(ref _reconnectObserved, true); + } + public void DelayDestroy() { _delayDestroy = true; @@ -3233,8 +3974,9 @@ private async Task RunAsync() { if (root.TryGetProperty("error", out var error)) { - completion.TrySetException(new InvalidOperationException( - error.GetProperty("message").GetString())); + var exception = new InvalidOperationException(error.GetProperty("message").GetString()); + exception.Data["error"] = error.Clone(); + completion.TrySetException(exception); } else { @@ -3347,6 +4089,10 @@ private async Task HandleRequestAsync(Stream stream, JsonElement request, Cancel ["sessionId"] = paramsElement.GetProperty("sessionId").GetString(), ["sessionUri"] = "ahp-session:/" + paramsElement.GetProperty("sessionId").GetString() }, + "host.listSessions" => new Dictionary + { + ["sessions"] = Array.Empty() + }, "session.eventLog.registerInterest" => new Dictionary { ["id"] = "interest-1" diff --git a/dotnet/test/Unit/ClientSessionSkillProviderTests.cs b/dotnet/test/Unit/ClientSessionSkillProviderTests.cs new file mode 100644 index 0000000000..c99d1f090a --- /dev/null +++ b/dotnet/test/Unit/ClientSessionSkillProviderTests.cs @@ -0,0 +1,397 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +#if NET8_0_OR_GREATER +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed partial class ClientSessionLifetimeTests +{ + [Fact] + public async Task SkillProvider_Create_And_Resume_Set_Flag_Only_When_Provided() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var provider = new TestSkillProvider + { + ReadHandler = (name, _) => Task.FromResult($"# {name}") + }; + + await using var created = await client.CreateSessionAsync(new SessionConfig + { + SessionId = "skill-create", + SkillProvider = provider + }); + await using var resumed = await client.ResumeSessionAsync("skill-resume", new ResumeSessionConfig + { + SkillProvider = provider + }); + + Assert.True(Assert.Single(server.Requests, request => request.Method == "session.create") + .Params.GetProperty("hasSkillProvider").GetBoolean()); + Assert.True(Assert.Single(server.Requests, request => request.Method == "session.resume") + .Params.GetProperty("hasSkillProvider").GetBoolean()); + + var read = await server.SendRequestAsync("skillProvider.read", SkillReadRequest(resumed.SessionId, "resumed-skill")); + Assert.Equal("# resumed-skill", read.GetProperty("markdown").GetString()); + + await created.DisposeAsync(); + await resumed.DisposeAsync(); + server.ClearRequests(); + + await using var createWithoutProvider = await client.CreateSessionAsync(new SessionConfig + { + SessionId = "skill-create-no-provider" + }); + await using var resumeWithoutProvider = await client.ResumeSessionAsync("skill-resume-no-provider", new ResumeSessionConfig()); + + Assert.False(Assert.Single(server.Requests, request => request.Method == "session.create") + .Params.TryGetProperty("hasSkillProvider", out _)); + Assert.False(Assert.Single(server.Requests, request => request.Method == "session.resume") + .Params.TryGetProperty("hasSkillProvider", out _)); + } + + [Fact] + public async Task SkillProvider_Callbacks_Work_Before_Create_And_Resume_Response() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var provider = new TestSkillProvider(); + var callbackResults = new List>(); + server.BeforeResponseAsync = async (request, _) => + { + if (request.Method is "session.create" or "session.resume" + && request.Params.TryGetProperty("sessionId", out var sessionId)) + { + callbackResults.Add(await server.SendRequestWithoutWaitingAsync( + "skillProvider.list", + SkillListRequest(sessionId.GetString()!))); + } + }; + + await using var created = await client.CreateSessionAsync(new SessionConfig + { + SessionId = "pre-response-create", + SkillProvider = provider + }); + await using var resumed = await client.ResumeSessionAsync("pre-response-resume", new ResumeSessionConfig + { + SkillProvider = provider + }); + + Assert.Equal(2, callbackResults.Count); + foreach (var callback in callbackResults) + { + var result = await callback.WaitAsync(TimeSpan.FromSeconds(5)); + Assert.Equal("dynamic", Assert.Single(result.GetProperty("skills").EnumerateArray()).GetProperty("name").GetString()); + } + } + + [Fact] + public async Task SkillProvider_List_Returns_CamelCase_Descriptors_And_Omits_Null_Optionals() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var provider = new TestSkillProvider + { + ListHandler = _ => Task.FromResult>( + [ + new() + { + Name = "basic", + Description = "Basic skill" + }, + new() + { + Name = "advanced", + Description = "Advanced skill", + UserInvocable = false, + DisableModelInvocation = true, + ArgumentHint = "" + } + ]) + }; + await using var session = await client.CreateSessionAsync(new SessionConfig { SkillProvider = provider }); + + var result = await server.SendRequestAsync("skillProvider.list", SkillListRequest(session.SessionId)); + var skills = result.GetProperty("skills").EnumerateArray().ToArray(); + + Assert.Equal("basic", skills[0].GetProperty("name").GetString()); + Assert.Equal("Basic skill", skills[0].GetProperty("description").GetString()); + Assert.False(skills[0].TryGetProperty("userInvocable", out _)); + Assert.False(skills[0].TryGetProperty("disableModelInvocation", out _)); + Assert.False(skills[0].TryGetProperty("argumentHint", out _)); + Assert.False(skills[0].TryGetProperty("UserInvocable", out _)); + Assert.False(skills[0].TryGetProperty("DisableModelInvocation", out _)); + Assert.False(skills[0].TryGetProperty("ArgumentHint", out _)); + Assert.Equal("advanced", skills[1].GetProperty("name").GetString()); + Assert.False(skills[1].GetProperty("userInvocable").GetBoolean()); + Assert.True(skills[1].GetProperty("disableModelInvocation").GetBoolean()); + Assert.Equal("", skills[1].GetProperty("argumentHint").GetString()); + } + + [Fact] + public async Task SkillProvider_Null_List_Result_Is_Empty() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var provider = new TestSkillProvider + { + ListHandler = _ => Task.FromResult>(null!) + }; + await using var session = await client.CreateSessionAsync(new SessionConfig { SkillProvider = provider }); + + var result = await server.SendRequestAsync("skillProvider.list", SkillListRequest(session.SessionId)); + + Assert.Empty(result.GetProperty("skills").EnumerateArray()); + } + + [Fact] + public async Task SkillProvider_Read_Returns_Markdown_And_Null_For_Missing_Skill() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var provider = new TestSkillProvider + { + ReadHandler = (name, _) => Task.FromResult(name == "known" ? "# Known" : null) + }; + await using var session = await client.CreateSessionAsync(new SessionConfig { SkillProvider = provider }); + + var read = await server.SendRequestAsync("skillProvider.read", SkillReadRequest(session.SessionId, "known")); + + Assert.Equal("# Known", read.GetProperty("markdown").GetString()); + var missing = await server.SendRequestAsync("skillProvider.read", SkillReadRequest(session.SessionId, "missing")); + Assert.True(missing.TryGetProperty("markdown", out var markdown), missing.ToString()); + Assert.Equal(JsonValueKind.Null, markdown.ValueKind); + } + + [Fact] + public async Task SkillProvider_Provider_Failures_Do_Not_Leak_Exception_Details() + { + await using var server = await FakeCopilotServer.StartAsync(); + var logger = new SkillProviderLogger(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url), Logger = logger }); + var listFailure = new InvalidOperationException("secret list failure"); + var readFailure = new InvalidOperationException("secret read failure"); + var provider = new TestSkillProvider + { + ListHandler = _ => throw listFailure, + ReadHandler = (_, _) => throw readFailure + }; + await using var session = await client.CreateSessionAsync(new SessionConfig { SkillProvider = provider }); + + var listError = await Assert.ThrowsAsync(() => + server.SendRequestAsync("skillProvider.list", SkillListRequest(session.SessionId))); + AssertRpcError(listError, "Skill provider listSkills failed"); + + var readError = await Assert.ThrowsAsync(() => + server.SendRequestAsync("skillProvider.read", SkillReadRequest(session.SessionId, "throws"))); + AssertRpcError(readError, "Skill provider readSkill failed"); + + Assert.DoesNotContain("secret", listError.Message, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("secret", readError.Message, StringComparison.OrdinalIgnoreCase); + Assert.Contains(logger.Entries, entry => + entry.Message == $"Skill provider listSkills failed. SessionId={session.SessionId}" && entry.Exception == listFailure); + Assert.Contains(logger.Entries, entry => + entry.Message == $"Skill provider readSkill failed. SessionId={session.SessionId}" && entry.Exception == readFailure); + } + + [Fact] + public async Task SkillProvider_Provider_Cancellation_Without_Request_Cancellation_Is_Provider_Failure() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var provider = new TestSkillProvider + { + ListHandler = _ => throw new TaskCanceledException("secret list timeout"), + ReadHandler = (_, _) => throw new TaskCanceledException("secret read timeout") + }; + await using var session = await client.CreateSessionAsync(new SessionConfig { SkillProvider = provider }); + + var listError = await Assert.ThrowsAsync(() => + server.SendRequestAsync("skillProvider.list", SkillListRequest(session.SessionId)).WaitAsync(TimeSpan.FromSeconds(10))); + AssertRpcError(listError, "Skill provider listSkills failed"); + + var readError = await Assert.ThrowsAsync(() => + server.SendRequestAsync("skillProvider.read", SkillReadRequest(session.SessionId, "times-out")).WaitAsync(TimeSpan.FromSeconds(10))); + AssertRpcError(readError, "Skill provider readSkill failed"); + } + + [Fact] + public async Task SkillProvider_Rejects_Unknown_NoProvider_And_Disposed_Sessions() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + await client.StartAsync(); + + var unknown = await Assert.ThrowsAsync(() => + server.SendRequestAsync("skillProvider.list", SkillListRequest("unknown-session"))); + AssertRpcError(unknown, "No skill provider for session: unknown-session"); + + await using var noProvider = await client.CreateSessionAsync(new SessionConfig { SessionId = "no-provider" }); + var noProviderError = await Assert.ThrowsAsync(() => + server.SendRequestAsync("skillProvider.list", SkillListRequest(noProvider.SessionId))); + AssertRpcError(noProviderError, "No skill provider for session: no-provider"); + + var providerSession = await client.CreateSessionAsync(new SessionConfig + { + SessionId = "disposed-provider", + SkillProvider = new TestSkillProvider() + }); + await providerSession.DisposeAsync(); + var disposed = await Assert.ThrowsAsync(() => + server.SendRequestAsync("skillProvider.list", SkillListRequest("disposed-provider"))); + AssertRpcError(disposed, "No skill provider for session: disposed-provider"); + } + + [Fact] + public async Task SkillProvider_Cloud_Create_Throws_Before_Connecting() + { + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri("http://127.0.0.1:1") + }); + var provider = new TestSkillProvider(); + + var error = await Assert.ThrowsAsync(() => client.CreateSessionAsync(new SessionConfig + { + Cloud = new CloudSessionOptions + { + Repository = new CloudSessionRepository + { + Owner = "github", + Name = "copilot-sdk", + Branch = "main" + } + }, + SkillProvider = provider + })); + + Assert.Equal("Skill providers are not supported for cloud sessions.", error.Message); + Assert.Equal(0, provider.ListCalls); + Assert.Equal(0, provider.ReadCalls); + } + + [Fact] + public async Task SkillProvider_EmptyMode_Defaults_EnableSkills_To_False() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url), + Mode = CopilotClientMode.Empty, + BaseDirectory = Path.GetTempPath(), + }); + + await using var session = await client.CreateSessionAsync(new SessionConfig + { + AvailableTools = [], + SkillProvider = new TestSkillProvider() + }); + + var request = Assert.Single(server.Requests, request => request.Method == "session.create"); + Assert.True(request.Params.GetProperty("hasSkillProvider").GetBoolean()); + Assert.False(request.Params.GetProperty("enableSkills").GetBoolean()); + } + + private static Dictionary SkillListRequest(string sessionId) => new() + { + ["sessionId"] = sessionId + }; + + private static Dictionary SkillReadRequest(string sessionId, string name) => new() + { + ["sessionId"] = sessionId, + ["name"] = name + }; + + private static void AssertRpcError(InvalidOperationException exception, string expectedMessage) + { + Assert.Equal(expectedMessage, exception.Message); + var error = Assert.IsType(exception.Data["error"]); + Assert.Equal(-32603, error.GetProperty("code").GetInt32()); + Assert.Equal(expectedMessage, error.GetProperty("message").GetString()); + Assert.False(error.TryGetProperty("data", out _), error.ToString()); + } + + private sealed class SkillProviderLogger : ILogger + { + private readonly ConcurrentQueue<(string Message, Exception? Exception)> _entries = new(); + + public IReadOnlyCollection<(string Message, Exception? Exception)> Entries => _entries; + + public IDisposable? BeginScope(TState state) where TState : notnull => null; + + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) => + _entries.Enqueue((formatter(state, exception), exception)); + } + + private sealed class TestSkillProvider : ISkillProvider + { + public int ListCalls; + public int ReadCalls; + + public Func>> ListHandler { get; init; } = + _ => Task.FromResult>( + [ + new() + { + Name = "dynamic", + Description = "Dynamic skill" + } + ]); + + public Func> ReadHandler { get; init; } = + (name, _) => Task.FromResult($"# {name}"); + + public Task> ListSkillsAsync(CancellationToken cancellationToken) + { + Interlocked.Increment(ref ListCalls); + return ListHandler(cancellationToken); + } + + public Task ReadSkillAsync(string name, CancellationToken cancellationToken) + { + Interlocked.Increment(ref ReadCalls); + return ReadHandler(name, cancellationToken); + } + } + + private sealed partial class FakeCopilotServer + { + public async Task> SendRequestWithoutWaitingAsync(string method, Dictionary parameters) + { + var stream = _stream ?? throw new InvalidOperationException("Client is not connected."); + var id = Interlocked.Increment(ref _nextRequestId); + var completion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + if (!_pendingRequests.TryAdd(id, completion)) + { + throw new InvalidOperationException("Failed to track callback request."); + } + + await WriteMessageAsync(stream, new Dictionary + { + ["jsonrpc"] = "2.0", + ["id"] = id, + ["method"] = method, + ["params"] = parameters + }, _cts.Token); + + return completion.Task.WaitAsync(_cts.Token); + } + } +} +#endif diff --git a/dotnet/test/Unit/CloneTests.cs b/dotnet/test/Unit/CloneTests.cs index c67bce8b4a..3ae4c0b009 100644 --- a/dotnet/test/Unit/CloneTests.cs +++ b/dotnet/test/Unit/CloneTests.cs @@ -88,6 +88,15 @@ private sealed class TestExtensionLaunchProvider : GitHub.Copilot.Rpc.IExtension Task.FromResult(new GitHub.Copilot.Rpc.ExtensionLaunchProviderResolveResult()); } + private sealed class TestSkillProvider : ISkillProvider + { + public Task> ListSkillsAsync(CancellationToken cancellationToken) => + Task.FromResult>([]); + + public Task ReadSkillAsync(string name, CancellationToken cancellationToken) => + Task.FromResult(null); + } + [Fact] public void SessionConfig_Clone_CopiesAllProperties() { @@ -205,6 +214,28 @@ public void SessionConfig_RefreshCustomInstructions_IsCreateOnlyAndDefaultsToNul Assert.Null(typeof(ResumeSessionConfig).GetProperty(nameof(SessionConfig.RefreshCustomInstructions))); } + [Fact] + public void SessionConfig_Clone_CopiesSkillProvider() + { + var provider = new TestSkillProvider(); + var original = new SessionConfig { SkillProvider = provider }; + + var clone = original.Clone(); + + Assert.Same(provider, clone.SkillProvider); + } + + [Fact] + public void ResumeSessionConfig_Clone_CopiesSkillProvider() + { + var provider = new TestSkillProvider(); + var original = new ResumeSessionConfig { SkillProvider = provider }; + + var clone = original.Clone(); + + Assert.Same(provider, clone.SkillProvider); + } + [Fact] public void SessionConfig_Clone_CollectionsAreIndependent() { diff --git a/dotnet/test/Unit/E2ETestFixtureTests.cs b/dotnet/test/Unit/E2ETestFixtureTests.cs index 933b82c1fc..afbb87fd6f 100644 --- a/dotnet/test/Unit/E2ETestFixtureTests.cs +++ b/dotnet/test/Unit/E2ETestFixtureTests.cs @@ -4,7 +4,11 @@ using System.ComponentModel; using System.Diagnostics; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Reflection; +using System.Text.Json; using GitHub.Copilot.Test.E2E; using GitHub.Copilot.Test.Harness; using Xunit; @@ -13,6 +17,25 @@ namespace GitHub.Copilot.Test.Unit; public class E2ETestFixtureTests { + [Fact] + public async Task Default_Telemetry_Endpoint_Uses_The_Owned_Proxy() + { + await using var context = await E2ETestContext.CreateAsync(); + using var client = new HttpClient(); + using var userRequest = new HttpRequestMessage(HttpMethod.Get, context.ProxyUrl + "/copilot_internal/user"); + userRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.GetEnvironment()["GH_TOKEN"]); + using var userResponse = await client.SendAsync(userRequest); + Assert.Equal(HttpStatusCode.OK, userResponse.StatusCode); + using var user = JsonDocument.Parse(await userResponse.Content.ReadAsStringAsync()); + var telemetryEndpoint = user.RootElement.GetProperty("endpoints").GetProperty("telemetry").GetString(); + Assert.Equal(context.ProxyUrl, telemetryEndpoint); + using var content = new StringContent("{}\n"); + using var telemetryResponse = await client.PostAsync(telemetryEndpoint + "/telemetry", content); + Assert.Equal(HttpStatusCode.NoContent, telemetryResponse.StatusCode); + Assert.Equal(string.Empty, await telemetryResponse.Content.ReadAsStringAsync()); + Assert.Empty(await context.GetExchangesAsync()); + } + [Fact] public async Task Failed_Process_Launch_Reclaims_Context_Directories() { diff --git a/dotnet/test/Unit/InProcessRuntimeArgumentsTests.cs b/dotnet/test/Unit/InProcessRuntimeArgumentsTests.cs new file mode 100644 index 0000000000..1dc5e4d93e --- /dev/null +++ b/dotnet/test/Unit/InProcessRuntimeArgumentsTests.cs @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +using System.Reflection; +using GitHub.Copilot.Test.Harness; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed class InProcessRuntimeArgumentsTests +{ + [Fact] + public void Integration_Id_Is_Forwarded_To_The_Native_Host() + { + InProcessEnvIsolation.Apply("GITHUB_COPILOT_INTEGRATION_ID", " microsoft/vscode "); + var method = typeof(CopilotClient).GetMethod( + "BuildInProcessRuntimeArguments", + BindingFlags.Static | BindingFlags.NonPublic); + Assert.NotNull(method); + + var args = Assert.IsType>( + method!.Invoke(null, [new CopilotClientOptions()])); + + Assert.Contains("--cli-login-sync-integration-id=microsoft/vscode", args); + } +} diff --git a/dotnet/test/Unit/MSBuildTargetsTests.cs b/dotnet/test/Unit/MSBuildTargetsTests.cs index 0d02767dec..2e855a29be 100644 --- a/dotnet/test/Unit/MSBuildTargetsTests.cs +++ b/dotnet/test/Unit/MSBuildTargetsTests.cs @@ -450,6 +450,11 @@ public static MSBuildSandbox Create(bool packAsTool = false, string version = "0 """; File.WriteAllText(Path.Combine(dir, "App.csproj"), csproj); + File.WriteAllText(Path.Combine(dir, "NuGet.Config"), + ""); + // Match the SDK used by setup restore, which provisioned the offline framework packs. + File.Copy(Path.Combine(Path.GetDirectoryName(TargetsFilePath)!, "..", "..", "global.json"), + Path.Combine(dir, "global.json")); File.WriteAllText( Path.Combine(dir, "Stub.cs"), packAsTool diff --git a/dotnet/test/Unit/RpcMcpListTests.cs b/dotnet/test/Unit/RpcMcpListTests.cs new file mode 100644 index 0000000000..a662d49212 --- /dev/null +++ b/dotnet/test/Unit/RpcMcpListTests.cs @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +#if NET8_0_OR_GREATER +using System.Text.Json; +using GitHub.Copilot.Rpc; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed partial class ClientSessionLifetimeTests +{ + private static readonly string[] ExpectedMcpLifecycleStatuses = ["not_configured", "connected", "needs-auth", "stopped", "failed"]; + + [Fact] + public async Task Session_Rpc_Mcp_ListConfigured_Preserves_Runtime_Lifecycle() + { + await using var server = await FakeCopilotServer.StartAsync(); + using var response = JsonDocument.Parse(""" + { + "servers": [ + { "name": "cold", "enabled": true, "live": { "status": "not_configured" } }, + { "name": "old-connection", "enabled": false, "live": { "status": "connected" } }, + { "name": "auth", "enabled": true, "live": { "status": "needs-auth" } }, + { "name": "stopped", "enabled": true, "live": { "status": "stopped" } }, + { "name": "failed", "enabled": true, "live": { "status": "failed", "error": "connection failed" } } + ] + } + """); + server.ResponseFactory = _ => response.RootElement; + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + server.ClearRequests(); + + var inventory = await session.Rpc.Mcp.ListConfiguredAsync(); + Assert.Equal( + ExpectedMcpLifecycleStatuses, + inventory.Servers.Select(entry => entry.Live.Status.Value)); + Assert.False(inventory.Servers[1].Enabled); + Assert.Equal("connection failed", inventory.Servers[4].Live.Error); + AssertConnectorRequest(Assert.Single(server.Requests), "session.mcp.listConfigured", session.SessionId); + } + + [Fact] + public async Task Session_Rpc_Mcp_List_And_ListConfigured_Use_Parameterless_Wire_Contracts() + { + await using var server = await FakeCopilotServer.StartAsync(); + server.ResponseFactory = _ => new Dictionary { ["servers"] = Array.Empty() }; + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + server.ClearRequests(); + + var mcp = session.Rpc.Mcp; + Func> legacyList = mcp.ListAsync; + Func> configuredList = mcp.ListConfiguredAsync; + Assert.NotNull(mcp.GetType().GetMethod("ListAsync", [typeof(CancellationToken)])); + Assert.NotNull(mcp.GetType().GetMethod("ListConfiguredAsync", [typeof(CancellationToken)])); + await mcp.ListAsync(); + await legacyList(CancellationToken.None); + await mcp.ListConfiguredAsync(); + await configuredList(CancellationToken.None); + + Assert.Collection( + server.Requests, + request => AssertConnectorRequest(request, "session.mcp.list", session.SessionId), + request => AssertConnectorRequest(request, "session.mcp.list", session.SessionId), + request => AssertConnectorRequest(request, "session.mcp.listConfigured", session.SessionId), + request => AssertConnectorRequest(request, "session.mcp.listConfigured", session.SessionId)); + } +} +#endif diff --git a/dotnet/test/Unit/RpcModelCompatibilityTests.cs b/dotnet/test/Unit/RpcModelCompatibilityTests.cs new file mode 100644 index 0000000000..d638c86d35 --- /dev/null +++ b/dotnet/test/Unit/RpcModelCompatibilityTests.cs @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +#if NET8_0_OR_GREATER +using GitHub.Copilot.Rpc; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed partial class ClientSessionLifetimeTests +{ + [Fact] + public void Existing_Model_Switch_Signature_And_Defaults_Are_Preserved() + { + Type[] types = + [ + typeof(string), typeof(AutoTier?), typeof(string), typeof(ReasoningSummary?), + typeof(Verbosity?), typeof(ModelCapabilitiesOverride), typeof(ContextTier?), + typeof(ModelChangeSource?), typeof(bool?), typeof(string), typeof(bool?), + typeof(string), typeof(string), typeof(bool?), typeof(ModelPickerPersistenceRequest), + typeof(CancellationToken), + ]; + var method = typeof(ModelApi).GetMethod("SwitchToAsync", types); + Assert.NotNull(method); + var parameters = method.GetParameters(); + Assert.False(parameters[0].IsOptional); + Assert.Equal("cancellationToken", parameters[^1].Name); + Assert.All(parameters.Skip(1), parameter => + { + Assert.True(parameter.IsOptional); + Assert.True(parameter.HasDefaultValue); + Assert.Null(parameter.DefaultValue); + }); + } + + [Fact] + public async Task Existing_Positional_Model_Switch_Calls_Preserve_Wire_Values() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + server.ClearRequests(); + + await session.Rpc.Model.SwitchToAsync("auto", AutoTier.Balance); + await session.Rpc.Model.SwitchToAsync( + "auto", AutoTier.Efficiency, "high", null, null, null, null, null, + true, "compact", true, "repo", "global", true, null, CancellationToken.None); + + var requests = server.Requests.ToArray(); + Assert.Equal(2, requests.Length); + foreach (var request in requests) + { + Assert.Equal("session.model.switchTo", request.Method); + Assert.Equal(session.SessionId, request.Params.GetProperty("sessionId").GetString()); + Assert.Equal("auto", request.Params.GetProperty("modelId").GetString()); + Assert.False(request.Params.TryGetProperty("providerId", out _)); + } + Assert.Equal("balance", requests[0].Params.GetProperty("autoTier").GetString()); + Assert.False(requests[0].Params.TryGetProperty("reasoningEffort", out _)); + Assert.Equal("efficiency", requests[1].Params.GetProperty("autoTier").GetString()); + Assert.Equal("high", requests[1].Params.GetProperty("reasoningEffort").GetString()); + Assert.True(requests[1].Params.GetProperty("deferIfModelChangeQueued").GetBoolean()); + Assert.Equal("compact", requests[1].Params.GetProperty("compactionDecision").GetString()); + Assert.True(requests[1].Params.GetProperty("runCompactionPreflight").GetBoolean()); + Assert.Equal("repo", requests[1].Params.GetProperty("repoScope").GetString()); + Assert.Equal("global", requests[1].Params.GetProperty("modelChangeScope").GetString()); + Assert.True(requests[1].Params.GetProperty("requireAvailable").GetBoolean()); + } + + [Fact] + public async Task Provider_Qualified_Model_Switch_Uses_Request_With_Sdk_Owned_Session() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + server.ClearRequests(); + + var result = await session.Rpc.Model.SwitchToAsync(new ModelSwitchToRequest + { + ModelId = "shared-model", + ProviderId = "provider-a", + ReasoningEffort = "high", + }, CancellationToken.None); + + Assert.Null(typeof(ModelSwitchToRequest).GetProperty("SessionId")); + var request = Assert.Single(server.Requests); + Assert.Equal("session.model.switchTo", request.Method); + Assert.Equal(session.SessionId, request.Params.GetProperty("sessionId").GetString()); + Assert.Equal("shared-model", request.Params.GetProperty("modelId").GetString()); + Assert.Equal("provider-a", request.Params.GetProperty("providerId").GetString()); + Assert.Equal("high", request.Params.GetProperty("reasoningEffort").GetString()); + Assert.False(request.Params.TryGetProperty("autoTier", out _)); + // The fake reports "auto"; the SDK must return the server's result, not the requested id. + Assert.Equal("auto", result.ModelId); + } +} +#endif diff --git a/dotnet/test/Unit/RpcWorkspacesCompatibilityTests.cs b/dotnet/test/Unit/RpcWorkspacesCompatibilityTests.cs new file mode 100644 index 0000000000..8653a6b09a --- /dev/null +++ b/dotnet/test/Unit/RpcWorkspacesCompatibilityTests.cs @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +#if NET8_0_OR_GREATER +using GitHub.Copilot.Rpc; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed partial class ClientSessionLifetimeTests +{ + [Fact] + public void Workspace_Diff_Preserves_Existing_Signature_And_Defaults() + { + var method = typeof(WorkspacesApi).GetMethod("DiffAsync", + [typeof(WorkspaceDiffMode), typeof(bool?), typeof(CancellationToken)]); + Assert.NotNull(method); + Assert.Equal( + new (string? Name, bool IsOptional)[] + { + ("mode", false), + ("ignoreWhitespace", true), + ("cancellationToken", true), + }, + method.GetParameters().Select(parameter => (parameter.Name, parameter.IsOptional))); + Assert.All(method.GetParameters().Skip(1), parameter => Assert.Null(parameter.DefaultValue)); + } + + [Fact] + public async Task Workspace_Diff_Preserves_Positional_Calls_And_Offers_Contents_Through_Request() + { + await using var server = await FakeCopilotServer.StartAsync(); + server.ResponseFactory = request => request.Method == "session.workspaces.diff" + ? new Dictionary + { + ["mode"] = "session", + ["requestedMode"] = "session", + ["isFallback"] = false, + ["changes"] = Array.Empty(), + } + : throw new InvalidOperationException($"Unexpected workspace diff request '{request.Method}'."); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + server.ClearRequests(); + var cancellation = CancellationToken.None; + + await session.Rpc.Workspaces.DiffAsync(WorkspaceDiffMode.Session, false, cancellation); + await session.Rpc.Workspaces.DiffAsync(WorkspaceDiffMode.Session); + await session.Rpc.Workspaces.DiffAsync(WorkspaceDiffMode.Session, cancellationToken: cancellation); + await session.Rpc.Workspaces.DiffAsync(new WorkspacesDiffRequest + { + Mode = WorkspaceDiffMode.Session, + IgnoreWhitespace = false, + IncludeContents = true, + }, cancellation); + await session.Rpc.Workspaces.DiffAsync(new WorkspacesDiffRequest + { + Mode = WorkspaceDiffMode.Session, + IncludeContents = false, + }, cancellation); + + Assert.Null(typeof(WorkspacesDiffRequest).GetProperty("SessionId")); + var requests = server.Requests.ToArray(); + Assert.All(requests, request => Assert.Equal( + ("session.workspaces.diff", session.SessionId, "session"), + (request.Method, request.Params.GetProperty("sessionId").GetString(), + request.Params.GetProperty("mode").GetString()))); + Assert.Equal( + new (bool? IgnoreWhitespace, bool? IncludeContents)[] + { + (false, null), + (null, null), + (null, null), + (false, true), + (null, false), + }, + requests.Select(request => ( + request.Params.TryGetProperty("ignoreWhitespace", out var ignoreWhitespace) + ? ignoreWhitespace.GetBoolean() : (bool?)null, + request.Params.TryGetProperty("includeContents", out var includeContents) + ? includeContents.GetBoolean() : (bool?)null))); + } +} +#endif diff --git a/dotnet/test/Unit/RuntimeWrapperTests.cs b/dotnet/test/Unit/RuntimeWrapperTests.cs index e7c77ab92d..47bcba2ab6 100644 --- a/dotnet/test/Unit/RuntimeWrapperTests.cs +++ b/dotnet/test/Unit/RuntimeWrapperTests.cs @@ -93,7 +93,8 @@ public async Task Marked_Bundled_Explicit_Cli_Does_Not_Require_Runtime_Pair() var nativeDirectory = Path.Combine(baseDirectory, "runtimes", rid, "native"); Directory.CreateDirectory(nativeDirectory); var cliPath = Path.Combine(nativeDirectory, OperatingSystem.IsWindows() ? "copilot.exe" : "copilot"); - await File.WriteAllTextAsync(cliPath, "not an executable"); + // Nonempty invalid images can stall Windows process creation before it reports the launch error. + await File.WriteAllTextAsync(cliPath, string.Empty); await File.WriteAllTextAsync(Path.Combine(nativeDirectory, ".copilot-explicit-cli"), "explicit"); try diff --git a/dotnet/test/Unit/SerializationTests.cs b/dotnet/test/Unit/SerializationTests.cs index 30ac2608d6..ef41cfa4aa 100644 --- a/dotnet/test/Unit/SerializationTests.cs +++ b/dotnet/test/Unit/SerializationTests.cs @@ -1283,7 +1283,7 @@ public void ModelSwitchRequests_DistinguishRequiredNullFromOmittedOptionalValue( Assert.True(switchAutoTierDocument.RootElement.TryGetProperty("autoTier", out var requiredAutoTier)); Assert.Equal(JsonValueKind.Null, requiredAutoTier.ValueKind); - var switchToType = assembly.GetType("GitHub.Copilot.Rpc.ModelSwitchToRequest"); + var switchToType = assembly.GetType("GitHub.Copilot.Rpc.ModelSwitchToRequestWithSession"); Assert.NotNull(switchToType); var switchToRequest = CreateInternalRequest( switchToType!, diff --git a/dotnet/test/Unit/SetToolsTests.cs b/dotnet/test/Unit/SetToolsTests.cs index 4779a3a70e..c88dccb639 100644 --- a/dotnet/test/Unit/SetToolsTests.cs +++ b/dotnet/test/Unit/SetToolsTests.cs @@ -6,9 +6,11 @@ #pragma warning disable GHCP001 // Live tool replacement is intentionally experimental. using Microsoft.Extensions.AI; +using Microsoft.Extensions.Logging; using System.Net; using System.Net.Sockets; using System.Reflection; +using System.Runtime.ExceptionServices; using System.Text; using System.Text.Json; using System.Text.Json.Nodes; @@ -122,6 +124,53 @@ public async Task SetToolsAsync_Rejection_Leaves_Handlers_Unchanged() Assert.Equal("old", result); } + [Fact] + public async Task SetToolsAsync_Acceptance_After_Disposal_Cannot_Restore_Handlers_Or_Close_Connection() + { + await using var server = await SetToolsFakeServer.StartAsync(); + var releaseSet = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + server.BeforeSetToolsResponseAsync = _ => releaseSet.Task; + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + var replacement = session.SetToolsAsync([Tool("retired_tool", "must-not-install")]); + var timeout = TimeSpan.FromSeconds(5); + Exception? bodyFailure = null; + try + { + await server.WaitForRequestAsync("session.tools.set").WaitAsync(timeout); + await session.DisposeAsync().AsTask().WaitAsync(timeout); + releaseSet.TrySetResult(); + + await Assert.ThrowsAsync(() => replacement.WaitAsync(timeout)); + await using var liveSession = await client.CreateSessionAsync(new SessionConfig()).WaitAsync(timeout); + Assert.NotEqual(session.SessionId, liveSession.SessionId); + } + catch (Exception error) + { + bodyFailure = error; + } + finally + { + releaseSet.TrySetResult(); + try + { + await replacement.WaitAsync(timeout); + } + catch (ObjectDisposedException) + { + // The acknowledged replacement was rejected by local retirement. + } + catch (Exception cleanupError) + { + bodyFailure = bodyFailure is null ? cleanupError : new AggregateException(bodyFailure, cleanupError); + } + } + if (bodyFailure is not null) + { + ExceptionDispatchInfo.Capture(bodyFailure).Throw(); + } + } + [Fact] public async Task SetToolsAsync_Empty_Set_Removes_Handlers() { @@ -240,6 +289,40 @@ await Assert.ThrowsAnyAsync(() => Assert.Equal("new", response.Params.GetProperty("result").GetProperty("textResultForLlm").GetString()); } + [Fact] + public async Task SetToolsAsync_Publishes_Accepted_Replacement_Before_Next_Tool_Request() + { + await using var server = await SetToolsFakeServer.StartAsync(); + var logger = new SetToolsResponseLogger(); + var releaseSet = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + server.BeforeSetToolsResponseAsync = _ => releaseSet.Task; + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url), Logger = logger }); + await using var session = await client.CreateSessionAsync(new SessionConfig + { + Tools = [Tool("cancel_tool", "old")], + }); + + using var cts = new CancellationTokenSource(); + try + { + var replacement = session.SetToolsAsync([Tool("cancel_tool", "new")], cts.Token); + await server.WaitForRequestAsync("session.tools.set"); + await cts.CancelAsync(); + await Assert.ThrowsAnyAsync(() => replacement); + + releaseSet.SetResult(); + await logger.ResponseReceived.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + var result = await InvokeToolAsync(server, session, "cancel_tool", "cancel-request"); + Assert.Equal("new", result); + } + finally + { + releaseSet.TrySetResult(); + logger.ContinueResponse.TrySetResult(); + } + } + [Fact] public async Task SetToolsAsync_Cancellation_While_Queued_Does_Not_Send_Request() { @@ -274,6 +357,52 @@ await Assert.ThrowsAnyAsync(() => Assert.Equal("first", result); } + [Fact] + public async Task SetToolsAsync_Cancellation_Before_Queued_Waiter_Resumes_Does_Not_Send_Request() + { + await using var server = await SetToolsFakeServer.StartAsync(); + var releaseSet = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + server.BeforeSetToolsResponseAsync = _ => releaseSet.Task; + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + await using var session = await client.CreateSessionAsync(new SessionConfig()); + + var first = session.SetToolsAsync([Tool("queued_tool", "first")]); + await server.WaitForRequestAsync("session.tools.set"); + using var cts = new CancellationTokenSource(); + var context = new PausedContinuationContext(); + var previousContext = SynchronizationContext.Current; + Task queued; + try + { + SynchronizationContext.SetSynchronizationContext(context); + queued = session.SetToolsAsync([Tool("queued_tool", "queued")], cts.Token); + } + finally + { + SynchronizationContext.SetSynchronizationContext(previousContext); + releaseSet.TrySetResult(); + } + + await first; + var continuation = await context.Continuation.Task.WaitAsync(TimeSpan.FromSeconds(5)); + try + { + await cts.CancelAsync(); + await Assert.ThrowsAnyAsync(() => queued); + } + finally + { + continuation.Callback(continuation.State); + } + + // A later completed replacement proves the cancelled waiter has left the queue. + await session.SetToolsAsync([Tool("queued_tool", "last")]); + Assert.Equal( + ["Returns first", "Returns last"], + server.Requests.Where(request => request.Method == "session.tools.set") + .Select(request => request.Params.GetProperty("tools")[0].GetProperty("description").GetString())); + } + private static AIFunction Tool(string name, string result) { return AIFunctionFactory.Create( @@ -441,6 +570,40 @@ public void Dispose() } } + private sealed class PausedContinuationContext : SynchronizationContext + { + public TaskCompletionSource<(SendOrPostCallback Callback, object? State)> Continuation { get; } = + new(TaskCreationOptions.RunContinuationsAsynchronously); + + public override void Post(SendOrPostCallback callback, object? state) + { + if (!Continuation.TrySetResult((callback, state))) + { + base.Post(callback, state); + } + } + } + + private sealed class SetToolsResponseLogger : ILogger + { + public TaskCompletionSource ResponseReceived { get; } = new(TaskCreationOptions.RunContinuationsAsynchronously); + public TaskCompletionSource ContinueResponse { get; } = new(TaskCreationOptions.RunContinuationsAsynchronously); + public IDisposable? BeginScope(TState state) where TState : notnull => null; + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + { + if (state is IReadOnlyList> properties && + properties.Any(entry => entry is { Key: "Method", Value: "session.tools.set" }) && + properties.Any(entry => entry is { Key: "Status", Value: "Succeeded" })) + { + // Hold the RPC awaiter after acceptance without blocking the reader's next tool event. + ResponseReceived.TrySetResult(); + ContinueResponse.Task.GetAwaiter().GetResult(); + } + } + } + private sealed class SetToolsFakeServer : IAsyncDisposable { private static readonly JsonSerializerOptions s_jsonOptions = new(JsonSerializerDefaults.Web) @@ -453,6 +616,7 @@ private sealed class SetToolsFakeServer : IAsyncDisposable private readonly List _requests = []; private readonly object _requestsLock = new(); private readonly Task _serverTask; + private readonly List _requestTasks = []; private NetworkStream? _stream; private string? _nextSetToolsRejection; private readonly Dictionary _setToolsRejections = []; @@ -578,8 +742,19 @@ public async ValueTask DisposeAsync() { } - _cts.Dispose(); - _writeLock.Dispose(); + try + { + await Task.WhenAll(_requestTasks).WaitAsync(TimeSpan.FromSeconds(5)); + } + catch (OperationCanceledException) when (_requestTasks.All(task => task.IsCanceled || task.IsCompletedSuccessfully)) + { + // Shutdown cancellation may stop a writer, but every owned request must finish. + } + finally + { + _cts.Dispose(); + _writeLock.Dispose(); + } } private async Task RunAsync() @@ -602,7 +777,7 @@ private async Task RunAsync() continue; } - _ = HandleRequestAsync(stream, root, id.Clone(), _cts.Token); + _requestTasks.Add(HandleRequestAsync(stream, root, id.Clone(), _cts.Token)); } } diff --git a/go/README.md b/go/README.md index 000ae49086..fe297f069b 100644 --- a/go/README.md +++ b/go/README.md @@ -43,6 +43,12 @@ registers a Mission Control environment. Both can be enabled. Import `rpc` from Local hostname, port, token, and authentication settings belong inside `LocalServer`. The returned handle's `URL`, `Token`, `PID`, and `EnvironmentID` are optional pointers; Mission Control-only hosting has no local URL. These APIs are experimental. +Call `host.ListSessions(ctx)` to read the complete advertised catalog of live and +dormant sessions. +Set top-level `ComputeID` to reuse the durable catalog across local and Mission +Control hosting; it must agree with `GitHubEnvironment.ComputeID` when both are +supplied. The runtime persists an omitted local-only identity. Publication +survives host shutdown; dormant application sessions require your resume callback. Use the generated `client.RPC.Environments` namespace for environment list/get/delete operations. See [runtime-supervised AHP hosting](../docs/runtime-supervised-host.md) for creation and resume callbacks, resident-session publication, ownership, and shared-snapshot E2Es. @@ -145,6 +151,56 @@ Avoid logging it indiscriminately: server-provided data may contain sensitive information. Its fields and data bytes are shared with the wrapped error; copy them before mutation. +## Skill providers (experimental) + +Use `SessionConfig.SkillProvider` or `ResumeSessionConfig.SkillProvider` to +serve session-scoped skills from your application instead of from `SKILL.md` +files on disk. The provider is ephemeral: it is not serialized or persisted, so +re-supply it on every resume. Resuming without a provider unbinds any previous +provider for that session. + + + +```go +type memorySkillProvider struct{} + +func (memorySkillProvider) ListSkills(ctx context.Context) ([]rpc.SkillProviderDescriptor, error) { + return []rpc.SkillProviderDescriptor{{ + Name: "review", + Description: "Review code using the host application's policy", + }}, nil +} + +func (memorySkillProvider) ReadSkill(ctx context.Context, name string) (string, error) { + if name != "review" { + return "", copilot.ErrSkillNotFound + } + return "Review the changes and call out policy violations.", nil +} + +session, err := client.CreateSession(ctx, &copilot.SessionConfig{ + SkillProvider: memorySkillProvider{}, + // Required only when ClientOptions.Mode is ModeEmpty. + // EnableSkills: copilot.Bool(true), +}) +``` + +`ReadSkill` returns an error for which +`errors.Is(err, copilot.ErrSkillNotFound)` is true when a listed skill no +longer exists. Other errors are reported to the runtime as generic provider +failures so provider error text is not exposed to the model. + +Skill providers are not supported for cloud sessions. Creating a cloud session +with a provider fails before the client connects with: +`Skill providers are not supported for cloud sessions.` + +Provider methods can be called concurrently by the runtime, including from +sub-agents that inherit the root session binding. Implementations must be safe +for concurrent calls and should observe the `context.Context`. The context is +cancelled when the runtime abandons the request: the call times out, the +session disconnects or is deleted, or a resume replaces the provider. It is not +cancelled when the connection closes or the client is force-stopped. + ## Installation confirmation (experimental) Set `ClientOptions.InstallationConfirmationHandler` to receive the runtime's @@ -257,7 +313,8 @@ Implemented with pure-Go FFI (via [purego](https://github.com/ebitengine/purego) - `NewClient(options *ClientOptions) *Client` - Create a new client - `Start(ctx context.Context) error` - Start the CLI server - `Stop() error` - Gracefully stop the CLI server. For an owned stdio process, requests runtime shutdown, closes stdin, and waits up to 10 seconds for host cleanup (including telemetry) and natural exit before falling back to a forced termination. -- `ForceStop()` - Forcefully stop without graceful cleanup +- `ForceStop()` - Forcefully stop without graceful RPC cleanup. Retires local event subscriptions and session callbacks, including entries held by dispatch snapshots or unsubscribe handles. Pending response waits fail without waiting for idle or their context deadlines; already-dispatched handlers are not joined. Late event registration is logged and returns a no-op unsubscribe, and a late tool-replacement acknowledgment cannot restore retired handlers. +- A plain `SendAndWait` that has already received its terminal idle or error preserves that result when local session retirement races the wait. An earlier event handler may also call `Disconnect` on the terminal event without losing that result. Without retirement, the wait still lets earlier synchronous handlers finish; a forced stop does not join those handlers or complete waits whose terminal dispatch they are still blocking. - `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 diff --git a/go/client.go b/go/client.go index 3b61dc4e3f..2d77f82956 100644 --- a/go/client.go +++ b/go/client.go @@ -42,6 +42,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime/debug" "strconv" "strings" "sync" @@ -60,6 +61,12 @@ import ( // whole-session [ProviderConfig]. Named providers are keyed by their own Name. const defaultBearerTokenProviderName = "default" +type cloudSkillProviderError struct{} + +func (cloudSkillProviderError) Error() string { + return "Skill providers are not supported for cloud sessions." +} + // collectBearerTokenProviders gathers the per-provider [BearerTokenProvider] callbacks // from the singular provider and any named providers, keyed by provider name. The // singular provider uses the implicit name "default"; named providers use their @@ -715,6 +722,14 @@ func (c *Client) logDebugTiming(start time.Time, message string) { // - Force closes the connection // - Kills the CLI process (if spawned by this client) // +// Event processing observes the stop signal before dispatching each remaining +// callback. Callbacks already being dispatched are not awaited and may finish +// after this method returns; an event handler can itself call ForceStop. +// Pending response waits fail when the session is retired, without waiting for +// an idle event or their context deadline. +// Registered session callbacks are released locally, including unadmitted event +// handler entries retained by a dispatch snapshot. +// // Example: // // // If normal stop hangs, force stop @@ -747,7 +762,9 @@ func (c *Client) ForceStop() { c.sessions = make(map[string]*Session) c.sessionsMux.Unlock() for _, session := range sessions { + session.clearSkillProvider() session.cancelPendingExternalTools() + session.stopEventProcessing() } c.clearGitHubTokenProviders() c.closeCopilotRequestAdapter() @@ -876,6 +893,9 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses if config == nil { config = &SessionConfig{} } + if config.Cloud != nil && config.SkillProvider != nil { + return nil, cloudSkillProviderError{} + } if config.GitHubToken != "" && config.GitHubTokenProvider != nil { return nil, fmt.Errorf("GitHubToken and GitHubTokenProvider cannot be used together") } @@ -913,6 +933,9 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses req.EnableHostGitOperations = config.EnableHostGitOperations req.EnableSessionStore = config.EnableSessionStore req.EnableSkills = config.EnableSkills + if config.SkillProvider != nil { + req.HasSkillProvider = Bool(true) + } req.Tools = config.Tools systemMessage := c.systemMessageForMode(config.SystemMessage) wireSystemMessage, transformCallbacks := extractTransformCallbacks(systemMessage) @@ -952,6 +975,8 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses req.DefaultAgent = config.DefaultAgent req.Agent = config.Agent req.SkillDirectories = config.SkillDirectories + req.AgentDirectories = config.AgentDirectories + req.HookDirectories = config.HookDirectories req.PluginDirectories = config.PluginDirectories req.InstructionDirectories = config.InstructionDirectories req.DisabledSkills = config.DisabledSkills @@ -961,6 +986,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses req.InfiniteSessions = config.InfiniteSessions req.LargeOutput = config.LargeOutput req.ToolSearch = config.ToolSearch + req.ImageGeneration = config.ImageGeneration req.Memory = config.Memory req.GitHubToken = config.GitHubToken req.GitHubTokenProviderRegistrationID = registrationID @@ -978,6 +1004,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses req.FeatureFlags = &config.FeatureFlags } req.EnableManagedSettings = config.EnableManagedSettings + req.EnforceManagedModelDefaults = config.EnforceManagedModelDefaults req.ManagedSettings = config.ManagedSettings if len(config.Commands) > 0 { @@ -1054,6 +1081,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses localSessionID = uuid.NewString() } req.SessionID = localSessionID + req.Name = config.Name // unregisterSession removes only the session created by this call and stops // its event consumer. The latter is essential on CreateSession error paths: @@ -1112,6 +1140,9 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses if config.CanvasHandler != nil { s.registerCanvasHandler(config.CanvasHandler) } + if config.SkillProvider != nil { + s.registerSkillProvider(config.SkillProvider) + } if bearerTokenProviders := collectBearerTokenProviders(config.Provider, config.Providers); bearerTokenProviders != nil { s.registerBearerTokenProviders(bearerTokenProviders) } @@ -1411,6 +1442,9 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, req.EnableHostGitOperations = config.EnableHostGitOperations req.EnableSessionStore = config.EnableSessionStore req.EnableSkills = config.EnableSkills + if config.SkillProvider != nil { + req.HasSkillProvider = Bool(true) + } if config.SuppressResumeEvent { req.DisableResume = Bool(true) } @@ -1425,6 +1459,8 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, req.DefaultAgent = config.DefaultAgent req.Agent = config.Agent req.SkillDirectories = config.SkillDirectories + req.AgentDirectories = config.AgentDirectories + req.HookDirectories = config.HookDirectories req.PluginDirectories = config.PluginDirectories req.InstructionDirectories = config.InstructionDirectories req.DisabledSkills = config.DisabledSkills @@ -1434,6 +1470,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, req.InfiniteSessions = config.InfiniteSessions req.LargeOutput = config.LargeOutput req.ToolSearch = config.ToolSearch + req.ImageGeneration = config.ImageGeneration req.Memory = config.Memory req.GitHubToken = config.GitHubToken req.GitHubTokenProviderRegistrationID = registrationID @@ -1451,6 +1488,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, req.FeatureFlags = &config.FeatureFlags } req.EnableManagedSettings = config.EnableManagedSettings + req.EnforceManagedModelDefaults = config.EnforceManagedModelDefaults req.ManagedSettings = config.ManagedSettings if config.OnPermissionRequest != nil { req.RequestPermission = Bool(true) @@ -1520,6 +1558,9 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, if config.CanvasHandler != nil { session.registerCanvasHandler(config.CanvasHandler) } + if config.SkillProvider != nil { + session.registerSkillProvider(config.SkillProvider) + } if bearerTokenProviders := collectBearerTokenProviders(config.Provider, config.Providers); bearerTokenProviders != nil { session.registerBearerTokenProviders(bearerTokenProviders) } @@ -1743,6 +1784,7 @@ func (c *Client) DeleteSession(ctx context.Context, sessionID string) error { delete(c.sessions, sessionID) c.sessionsMux.Unlock() if session != nil { + session.clearSkillProvider() session.releaseGitHubTokenProviderRegistration() } @@ -2389,7 +2431,8 @@ func (c *Client) startInProcess(ctx context.Context) error { return errors.New("in-process runtime unavailable: build with the bundled embedded runtime or set COPILOT_CLI_PATH to a compatible runtime package") } - config := c.inProcessHostConfig() + integrationID := strings.TrimSpace(getEnvValue(c.options.Env, "GITHUB_COPILOT_INTEGRATION_ID")) + config := c.inProcessHostConfig(integrationID) host, err := createInProcessHost(runtimePath, cliEntrypoint, config) if err != nil { @@ -2427,7 +2470,7 @@ func (c *Client) startInProcess(ctx context.Context) error { return nil } -func (c *Client) inProcessHostConfig() inProcessHostConfig { +func (c *Client) inProcessHostConfig(cliLoginSyncIntegrationID string) inProcessHostConfig { args := make([]string, 0, 8) if c.options.LogLevel != "" { args = append(args, "--log-level", c.options.LogLevel) @@ -2450,6 +2493,9 @@ func (c *Client) inProcessHostConfig() inProcessHostConfig { if c.options.EnableRemoteSessions { args = append(args, "--remote") } + if cliLoginSyncIntegrationID != "" { + args = append(args, "--cli-login-sync-integration-id="+cliLoginSyncIntegrationID) + } environment := make(map[string]string) if c.options.GitHubToken != "" { @@ -2590,6 +2636,8 @@ func (c *Client) setupNotificationHandler() { c.client.SetRequestHandler("exitPlanMode.request", jsonrpc2.RequestHandlerFor(c.handleExitPlanModeRequest)) c.client.SetRequestHandler("autoModeSwitch.request", jsonrpc2.RequestHandlerFor(c.handleAutoModeSwitchRequest)) c.client.SetRequestHandler("systemMessage.transform", jsonrpc2.RequestHandlerFor(c.handleSystemMessageTransform)) + c.client.SetRequestContextHandler("skillProvider.list", c.handleSkillProviderList) + c.client.SetRequestContextHandler("skillProvider.read", c.handleSkillProviderRead) rpc.RegisterClientSessionAPIHandlers(c.client, func(sessionID string) *rpc.ClientSessionAPIHandlers { c.sessionsMux.Lock() defer c.sessionsMux.Unlock() @@ -2684,6 +2732,7 @@ func (c *Client) handleConnectionClose() { } c.sessionsMux.Unlock() for _, session := range sessions { + session.clearSkillProvider() session.cancelPendingExternalTools() } // Avoid deadlocking with Stop/ForceStop, which hold startStopMux while @@ -2801,6 +2850,102 @@ func (c *Client) handleSessionEvent(req sessionEventRequest) { } } +func (c *Client) handleSkillProviderList(ctx context.Context, params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var req rpc.SkillProviderListRequest + if err := json.Unmarshal(params, &req); err != nil || req.SessionID == "" { + return nil, &jsonrpc2.Error{Code: -32602, Message: "invalid skill provider list payload"} + } + + provider, rpcErr := c.resolveSkillProvider(req.SessionID) + if rpcErr != nil { + return nil, rpcErr + } + + skills, err := callSkillProvider(ctx, req.SessionID, "listSkills", func() ([]rpc.SkillProviderDescriptor, error) { + return provider.ListSkills(ctx) + }) + if err != nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: "Skill provider listSkills failed"} + } + if skills == nil { + skills = []rpc.SkillProviderDescriptor{} + } + + raw, err := json.Marshal(rpc.SkillProviderListResult{Skills: skills}) + if err != nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("Failed to marshal response: %v", err)} + } + return raw, nil +} + +func (c *Client) handleSkillProviderRead(ctx context.Context, params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var req rpc.SkillProviderReadRequest + if err := json.Unmarshal(params, &req); err != nil || req.SessionID == "" || req.Name == "" { + return nil, &jsonrpc2.Error{Code: -32602, Message: "invalid skill provider read payload"} + } + + provider, rpcErr := c.resolveSkillProvider(req.SessionID) + if rpcErr != nil { + return nil, rpcErr + } + + // Classify not-found inside the guarded call: errors.Is runs provider + // Is/Unwrap methods, which may panic. + markdown, err := callSkillProvider(ctx, req.SessionID, "readSkill", func() (*string, error) { + markdown, err := provider.ReadSkill(ctx, req.Name) + if errors.Is(err, ErrSkillNotFound) { + return nil, nil + } + if err != nil { + return nil, err + } + return &markdown, nil + }) + if err != nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: "Skill provider readSkill failed"} + } + + raw, err := json.Marshal(rpc.SkillProviderReadResult{Markdown: markdown}) + if err != nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("Failed to marshal response: %v", err)} + } + return raw, nil +} + +func (c *Client) resolveSkillProvider(sessionID string) (SkillProvider, *jsonrpc2.Error) { + c.sessionsMux.Lock() + session := c.sessions[sessionID] + c.sessionsMux.Unlock() + if session == nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No skill provider for session: %s", sessionID)} + } + provider := session.getSkillProvider() + if provider == nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No skill provider for session: %s", sessionID)} + } + return provider, nil +} + +var errSkillProviderPanic = errors.New("skill provider panicked") + +// callSkillProvider logs provider failures locally and converts panics into +// an error, so the runtime only ever receives a generic failure. +func callSkillProvider[T any](ctx context.Context, sessionID, operation string, call func() (T, error)) (result T, err error) { + defer func() { + if failure := recover(); failure != nil { + log.Printf("skill provider %s panicked: session_id=%s panic=%v\n%s", operation, sessionID, failure, debug.Stack()) + var zero T + result, err = zero, errSkillProviderPanic + } + }() + result, err = call() + // A call the runtime cancelled is expected to fail; it isn't a provider failure. + if err != nil && ctx.Err() == nil { + log.Printf("skill provider %s failed: session_id=%s error=%v", operation, sessionID, err) + } + return result, err +} + // handleUserInputRequest handles a user input request from the CLI server. func (c *Client) handleUserInputRequest(req userInputRequest) (*userInputResponse, *jsonrpc2.Error) { if req.SessionID == "" || req.Question == "" { diff --git a/go/client_test.go b/go/client_test.go index d9f3ffc4cd..289a8e4735 100644 --- a/go/client_test.go +++ b/go/client_test.go @@ -545,9 +545,33 @@ func TestClient_ForceStopAndExternalStopDoNotRequestRuntimeShutdown(t *testing.T externalServer.Stop() } +func TestClient_ForceStopStopsRegisteredSessionEventProcessing(t *testing.T) { + rpcClient, server, shutdownCalled := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + sessions := make(map[string]*Session) + for _, id := range []string{"session-1", "session-2"} { + session := newSession(id, rpcClient, "", false) + t.Cleanup(session.stopEventProcessing) + sessions[id] = session + } + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: sessions, + } + + client.ForceStop() + for _, session := range sessions { + assertSessionEventChannelClosed(t, session) + } + client.ForceStop() + assertRuntimeShutdownNotCalled(t, shutdownCalled) +} + func TestClient_ForceStopCancelsPendingExternalTools(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) session := &Session{ + eventDone: make(chan struct{}), pendingExternalTools: map[string]*pendingExternalTool{ "request-1": {ctx: ctx, cancel: cancel}, }, @@ -567,6 +591,89 @@ func TestClient_ForceStopCancelsPendingExternalTools(t *testing.T) { } } +func TestClient_ForceStopDropsRemainingEventHandlers(t *testing.T) { + for _, fromHandler := range []bool{false, true} { + name := "while handler is blocked" + if fromHandler { + name = "from event handler" + } + t.Run(name, func(t *testing.T) { + session := &Session{ + eventCh: make(chan SessionEvent, 1), + eventDone: make(chan struct{}), + } + client := &Client{sessions: map[string]*Session{"session-1": session}} + entered := make(chan struct{}) + release := make(chan struct{}) + releaseHandler := sync.OnceFunc(func() { close(release) }) + forceStopped := make(chan struct{}) + consumerExited := make(chan struct{}) + unexpected := make(chan string, 3) + t.Cleanup(func() { + session.stopEventProcessing() + releaseHandler() + select { + case <-consumerExited: + case <-time.After(2 * time.Second): + t.Error("event consumer did not exit during cleanup") + } + }) + session.On(func(event SessionEvent) { + if _, ok := event.Data.(*SessionIdleData); !ok { + unexpected <- "queued event" + return + } + close(entered) + <-release + if fromHandler { + client.ForceStop() + close(forceStopped) + } + }) + session.On(func(SessionEvent) { unexpected <- "remaining handler" }) + go func() { + defer close(consumerExited) + session.processEvents() + }() + + session.eventCh <- newTestEvent() + select { + case <-entered: + case <-time.After(2 * time.Second): + t.Fatal("event handler did not enter its barrier") + } + session.eventCh <- SessionEvent{Data: &AssistantMessageData{ + Content: "queued", + MessageID: "queued", + }} + if fromHandler { + releaseHandler() + } else { + go func() { + client.ForceStop() + close(forceStopped) + }() + } + select { + case <-forceStopped: + case <-time.After(2 * time.Second): + t.Fatal("ForceStop waited for the in-flight event handler") + } + releaseHandler() + select { + case <-consumerExited: + case <-time.After(2 * time.Second): + t.Fatal("event consumer did not exit after the handler returned") + } + select { + case callback := <-unexpected: + t.Fatalf("ForceStop dispatched %s after cancellation", callback) + default: + } + }) + } +} + func TestClient_ConnectionCloseCancelsPendingExternalTools(t *testing.T) { rpcClient, server, _ := newRuntimeShutdownRpcPair(t) server.SetRequestHandler("session.detach", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { @@ -1992,7 +2099,7 @@ func TestClient_InProcessConnection(t *testing.T) { Mode: ModeEmpty, }) - config := client.inProcessHostConfig() + config := client.inProcessHostConfig("") expectedArgs := []string{ "--log-level", "debug", "--auth-token-env", "COPILOT_SDK_AUTH_TOKEN", @@ -2012,6 +2119,33 @@ func TestClient_InProcessConnection(t *testing.T) { t.Fatalf("Expected managed environment %v, got %v", expectedEnvironment, config.Environment) } }) + + t.Run("forwards supported CLI login sync integrations", func(t *testing.T) { + t.Setenv("GITHUB_COPILOT_INTEGRATION_ID", "github/github-app") + client := NewClient(&ClientOptions{Connection: InProcessConnection{}}) + t.Setenv("GITHUB_COPILOT_INTEGRATION_ID", "changed/after-construction") + + integrationID := getEnvValue(client.options.Env, "GITHUB_COPILOT_INTEGRATION_ID") + config := client.inProcessHostConfig(integrationID) + + expectedArgs := []string{"--cli-login-sync-integration-id=github/github-app"} + if !reflect.DeepEqual(config.Args, expectedArgs) { + t.Fatalf("Expected CLI login sync arguments %v, got %v", expectedArgs, config.Args) + } + }) + + t.Run("forwards integration validation to the runtime", func(t *testing.T) { + t.Setenv("GITHUB_COPILOT_INTEGRATION_ID", "third-party/integration") + client := NewClient(&ClientOptions{Connection: InProcessConnection{}}) + + integrationID := getEnvValue(client.options.Env, "GITHUB_COPILOT_INTEGRATION_ID") + config := client.inProcessHostConfig(integrationID) + + expectedArgs := []string{"--cli-login-sync-integration-id=third-party/integration"} + if !reflect.DeepEqual(config.Args, expectedArgs) { + t.Fatalf("Expected CLI login sync arguments %v, got %v", expectedArgs, config.Args) + } + }) } func TestClient_DefaultConnection(t *testing.T) { @@ -2178,6 +2312,38 @@ func TestCreateSessionRequest_ClientName(t *testing.T) { }) } +func TestCreateSessionRequest_Name(t *testing.T) { + t.Run("includes name in JSON when set", func(t *testing.T) { + req := createSessionRequest{Name: "named at create"} + 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["name"] != "named at create" { + t.Errorf("Expected name to be 'named at create', got %v", m["name"]) + } + }) + + t.Run("omits name from JSON when empty", func(t *testing.T) { + req := createSessionRequest{} + 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 _, ok := m["name"]; ok { + t.Error("Expected name to be omitted when empty") + } + }) +} + func TestResumeSessionRequest_ClientName(t *testing.T) { t.Run("includes clientName in JSON when set", func(t *testing.T) { req := resumeSessionRequest{SessionID: "s1", ClientName: "my-app"} @@ -5187,18 +5353,22 @@ func TestIsTerminal(t *testing.T) { func TestSessionRequests_ManagedSettings(t *testing.T) { settings := &ManagedSettings{ Permissions: &ManagedSettingsPermissions{ - DisableBypassPermissionsMode: DisableBypassPermissionsModeDisable, - Deny: []string{"Shell(git push)"}, - Ask: []string{"Domain(publish.example)"}, - Allow: []string{"Read(**)"}, + DisableBypassPermissionsMode: DisableBypassPermissionsModeDisable, + DisableAssistedPermissionsMode: Bool(true), + Deny: []string{"Shell(git push)"}, + Ask: []string{"Domain(publish.example)"}, + Allow: []string{"Read(**)"}, + LimitTo: []string{"Domain(github.com)"}, }, } expectedPermissions := map[string]any{ - "disableBypassPermissionsMode": "disable", - "deny": []any{"Shell(git push)"}, - "ask": []any{"Domain(publish.example)"}, - "allow": []any{"Read(**)"}, + "disableBypassPermissionsMode": "disable", + "disableAssistedPermissionsMode": true, + "deny": []any{"Shell(git push)"}, + "ask": []any{"Domain(publish.example)"}, + "allow": []any{"Read(**)"}, + "limitTo": []any{"Domain(github.com)"}, } t.Run("direct injection enables managed safeguards", func(t *testing.T) { @@ -5211,7 +5381,11 @@ func TestSessionRequests_ManagedSettings(t *testing.T) { }) t.Run("includes managedSettings on create when set", func(t *testing.T) { - req := createSessionRequest{EnableManagedSettings: Bool(true), ManagedSettings: settings} + req := createSessionRequest{ + EnableManagedSettings: Bool(true), + EnforceManagedModelDefaults: Bool(true), + ManagedSettings: settings, + } data, err := json.Marshal(req) if err != nil { t.Fatalf("Failed to marshal: %v", err) @@ -5223,6 +5397,9 @@ func TestSessionRequests_ManagedSettings(t *testing.T) { if m["enableManagedSettings"] != true { t.Errorf("Expected enableManagedSettings true, got %v", m["enableManagedSettings"]) } + if m["enforceManagedModelDefaults"] != true { + t.Errorf("Expected enforceManagedModelDefaults true, got %v", m["enforceManagedModelDefaults"]) + } ms, ok := m["managedSettings"].(map[string]any) if !ok { t.Fatalf("Expected managedSettings object, got %v", m["managedSettings"]) @@ -5290,6 +5467,7 @@ func TestSessionRequests_ManagedSettings(t *testing.T) { Deny: []string{}, Ask: []string{}, Allow: []string{}, + LimitTo: []string{}, }, }} data, err := json.Marshal(req) @@ -5302,7 +5480,7 @@ func TestSessionRequests_ManagedSettings(t *testing.T) { if perms["disableBypassPermissionsMode"] != "disable" { t.Errorf("Expected disableBypassPermissionsMode preserved, got %v", perms["disableBypassPermissionsMode"]) } - for _, key := range []string{"deny", "ask", "allow"} { + for _, key := range []string{"deny", "ask", "allow", "limitTo"} { if value, ok := perms[key].([]any); !ok || len(value) != 0 { t.Errorf("Expected %s to be an explicit empty array, got %v", key, perms[key]) } diff --git a/go/customization_directories_test.go b/go/customization_directories_test.go new file mode 100644 index 0000000000..7e7a638868 --- /dev/null +++ b/go/customization_directories_test.go @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package copilot + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/github/copilot-sdk/go/internal/jsonrpc2" + "github.com/github/copilot-sdk/go/rpc" +) + +func TestClient_CustomizationDirectoryAdapters(t *testing.T) { + for _, tt := range []struct { + name string + roots []string + }{ + {"omitted", nil}, + {"empty", []string{}}, + {"relative", []string{"relative-root", "other-root"}}, + } { + t.Run(tt.name, func(t *testing.T) { + directories := make(map[string][]string) + for key, suffix := range map[string]string{ + "skillDirectories": "skills", + "agentDirectories": "agents", + "instructionDirectories": "instructions", + "hookDirectories": "hooks", + } { + if tt.roots != nil { + directories[key] = make([]string, 0, len(tt.roots)) + for _, root := range tt.roots { + directories[key] = append(directories[key], root+"-"+suffix) + } + } + } + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + t.Cleanup(rpcClient.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + requests := make(chan json.RawMessage, 2) + for _, method := range []string{"session.create", "session.resume"} { + server.SetRequestHandler(method, func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + requests <- append(json.RawMessage(nil), params...) + id := sessionIDFromParams(t, params) + response, err := json.Marshal(map[string]string{"sessionId": id}) + if err != nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: err.Error()} + } + return response, nil + }) + } + _, err := client.CreateSession(t.Context(), &SessionConfig{ + WorkingDirectory: "request-cwd", + EnableConfigDiscovery: Bool(false), + EnableFileHooks: Bool(false), + SkillDirectories: directories["skillDirectories"], + AgentDirectories: directories["agentDirectories"], + InstructionDirectories: directories["instructionDirectories"], + HookDirectories: directories["hookDirectories"], + }) + if err != nil { + t.Fatal(err) + } + _, err = client.ResumeSessionWithOptions(t.Context(), "resumed", &ResumeSessionConfig{ + WorkingDirectory: "resume-cwd", + EnableConfigDiscovery: Bool(false), + EnableFileHooks: Bool(false), + SkillDirectories: directories["skillDirectories"], + AgentDirectories: directories["agentDirectories"], + InstructionDirectories: directories["instructionDirectories"], + HookDirectories: directories["hookDirectories"], + }) + if err != nil { + t.Fatal(err) + } + for range 2 { + var payload map[string]json.RawMessage + if err := json.Unmarshal(<-requests, &payload); err != nil { + t.Fatal(err) + } + for _, key := range []string{"skillDirectories", "agentDirectories", "instructionDirectories", "hookDirectories"} { + value, present := payload[key] + if tt.roots == nil { + if present { + t.Errorf("unexpected %s: %s", key, value) + } + } else { + var actual []string + if err := json.Unmarshal(value, &actual); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(actual, directories[key]) { + t.Errorf("%s = %#v, want %#v", key, actual, directories[key]) + } + } + } + for _, key := range []string{"enableConfigDiscovery", "enableFileHooks"} { + if string(payload[key]) != "false" { + t.Errorf("%s = %s, want false", key, payload[key]) + } + } + for _, key := range []string{"additionalDirectories", "customAgents", "hooks"} { + if _, present := payload[key]; present { + t.Errorf("unexpected %s in %s", key, payload[key]) + } + } + } + }) + } +} diff --git a/go/force_stop_test.go b/go/force_stop_test.go new file mode 100644 index 0000000000..89a5f6c874 --- /dev/null +++ b/go/force_stop_test.go @@ -0,0 +1,412 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package copilot_test + +import ( + "bufio" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "runtime" + "strconv" + "strings" + "sync" + "testing" + "time" + + copilot "github.com/github/copilot-sdk/go" +) + +type responseRetirementPeer struct { + listener net.Listener + mu sync.Mutex + conn net.Conn + writeMu sync.Mutex + sent chan struct{} + done chan error +} + +func newResponseRetirementPeer(t *testing.T, expectedSends int) *responseRetirementPeer { + t.Helper() + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + peer := &responseRetirementPeer{ + listener: listener, + sent: make(chan struct{}), + done: make(chan error, 1), + } + t.Cleanup(func() { + if err := listener.Close(); err != nil && !errors.Is(err, net.ErrClosed) { + t.Error("close peer listener:", err) + } + peer.mu.Lock() + conn := peer.conn + peer.mu.Unlock() + if conn != nil { + if err := conn.Close(); err != nil && !errors.Is(err, net.ErrClosed) { + t.Error("close peer connection:", err) + } + } + select { + case err := <-peer.done: + if err != nil { + t.Error("TCP peer:", err) + } + case <-time.After(5 * time.Second): + t.Error("TCP peer did not exit") + } + }) + go func() { peer.done <- peer.serve(expectedSends) }() + return peer +} + +func (p *responseRetirementPeer) serve(expectedSends int) error { + conn, err := p.listener.Accept() + if err != nil { + if errors.Is(err, net.ErrClosed) { + return nil + } + return err + } + p.mu.Lock() + p.conn = conn + p.mu.Unlock() + defer conn.Close() + reader := bufio.NewReader(conn) + sends := 0 + for { + frame, err := readRetirementFrame(reader) + if err != nil { + if errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) { + return nil + } + return err + } + var request struct { + ID json.RawMessage `json:"id"` + Method string `json:"method"` + } + if err := json.Unmarshal(frame, &request); err != nil { + return err + } + var result any + switch request.Method { + case "connect": + result = map[string]any{"ok": true, "protocolVersion": copilot.SDKProtocolVersion, "version": "force-stop-test"} + case "session.create": + result = map[string]any{"sessionId": "retirement-session"} + case "session.send": + sends++ + result = map[string]any{"messageId": fmt.Sprintf("message-%d", sends)} + case "ping": + result = map[string]any{"message": "pong", "timestamp": "2026-01-01T00:00:00Z", "protocolVersion": copilot.SDKProtocolVersion} + default: + return fmt.Errorf("unexpected RPC: %s", request.Method) + } + if err := p.write(map[string]any{"jsonrpc": "2.0", "id": request.ID, "result": result}); err != nil { + return err + } + if request.Method == "session.send" && sends == expectedSends { + close(p.sent) + } + } +} + +func readRetirementFrame(reader *bufio.Reader) ([]byte, error) { + length := -1 + for { + line, err := reader.ReadString('\n') + if err != nil { + if errors.Is(err, io.EOF) && line == "" && length == -1 { + return nil, io.EOF + } + return nil, fmt.Errorf("read frame header: %w", err) + } + if line == "\r\n" { + break + } + name, value, ok := strings.Cut(line, ":") + if !ok { + return nil, fmt.Errorf("invalid frame header: %q", line) + } + if strings.EqualFold(name, "Content-Length") { + if length != -1 { + return nil, errors.New("duplicate Content-Length") + } + length, err = strconv.Atoi(strings.TrimSpace(value)) + if err != nil { + return nil, err + } + } + } + if length <= 0 || length > 128*1024 { + return nil, fmt.Errorf("invalid frame length: %d", length) + } + body := make([]byte, length) + if _, err := io.ReadFull(reader, body); err != nil { + return nil, err + } + return body, nil +} + +func (p *responseRetirementPeer) write(message any) error { + body, err := json.Marshal(message) + if err != nil { + return err + } + p.writeMu.Lock() + defer p.writeMu.Unlock() + p.mu.Lock() + conn := p.conn + p.mu.Unlock() + _, err = fmt.Fprintf(conn, "Content-Length: %d\r\n\r\n%s", len(body), body) + return err +} + +type responseRetirementCapture struct { + data [64]byte +} + +func capturedRetirementHandler() (copilot.SessionEventHandler, <-chan struct{}) { + capture := &responseRetirementCapture{data: [64]byte{1}} + collected := make(chan struct{}) + runtime.AddCleanup(capture, func(done chan struct{}) { close(done) }, collected) + return func(copilot.SessionEvent) { runtime.KeepAlive(capture) }, collected +} + +func awaitRetirementCapture(t *testing.T, collected <-chan struct{}) { + t.Helper() + deadline := time.Now().Add(5 * time.Second) + for { + runtime.GC() + select { + case <-collected: + return + default: + } + if time.Now().After(deadline) { + t.Fatal("force-stopped retained session still roots an unadmitted callback capture") + } + runtime.Gosched() + } +} + +func TestForceStopReleasesRetainedEventCallbacks(t *testing.T) { + for _, blockedHandler := range []bool{false, true} { + t.Run(fmt.Sprintf("blocked handler=%t", blockedHandler), func(t *testing.T) { + t.Parallel() + peer := newResponseRetirementPeer(t, 0) + client := copilot.NewClient(&copilot.ClientOptions{ + Connection: copilot.URIConnection{URL: peer.listener.Addr().String()}, + }) + t.Cleanup(client.ForceStop) + ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) + defer cancel() + if err := client.Start(ctx); err != nil { + t.Fatal("start:", err) + } + session, err := client.CreateSession(ctx, &copilot.SessionConfig{ + SessionID: "retirement-session", OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + }) + if err != nil { + t.Fatal("create:", err) + } + entered := make(chan struct{}) + release := make(chan struct{}) + exited := make(chan struct{}) + admitted := false + releaseHandler := sync.OnceFunc(func() { close(release) }) + t.Cleanup(func() { + client.ForceStop() + releaseHandler() + if admitted { + select { + case <-exited: + case <-time.After(5 * time.Second): + t.Error("admitted event handler did not finish") + } + } + }) + if blockedHandler { + session.On(func(copilot.SessionEvent) { + close(entered) + <-release + close(exited) + }) + } + handler, collected := capturedRetirementHandler() + unsubscribe := session.On(handler) + if blockedHandler { + if err := peer.write(map[string]any{ + "jsonrpc": "2.0", "method": "session.event", + "params": map[string]any{ + "sessionId": session.SessionID, + "event": map[string]any{ + "id": "00000000-0000-4000-8000-000000000002", "parentId": nil, + "timestamp": "2026-01-01T00:00:00Z", "type": "session.idle", + "ephemeral": true, "data": map[string]any{}, + }, + }, + }); err != nil { + t.Fatal("notify:", err) + } + select { + case <-entered: + admitted = true + case <-ctx.Done(): + t.Fatal("event handler did not enter:", ctx.Err()) + } + } + client.ForceStop() + awaitRetirementCapture(t, collected) + runtime.KeepAlive(session) + runtime.KeepAlive(unsubscribe) + }) + } +} + +func createRetirementHookSession(t *testing.T, ctx context.Context, client *copilot.Client) (*copilot.Session, <-chan struct{}) { + t.Helper() + capture := &responseRetirementCapture{data: [64]byte{2}} + collected := make(chan struct{}) + runtime.AddCleanup(capture, func(done chan struct{}) { close(done) }, collected) + session, err := client.CreateSession(ctx, &copilot.SessionConfig{ + SessionID: "retirement-session", OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + Hooks: &copilot.SessionHooks{ + OnSessionEnd: func(copilot.SessionEndHookInput, copilot.HookInvocation) (*copilot.SessionEndHookOutput, error) { + runtime.KeepAlive(capture) + return nil, nil + }, + }, + }) + if err != nil { + t.Fatal("create:", err) + } + return session, collected +} + +func TestForceStopReleasesRetainedHookCallbacks(t *testing.T) { + peer := newResponseRetirementPeer(t, 0) + client := copilot.NewClient(&copilot.ClientOptions{ + Connection: copilot.URIConnection{URL: peer.listener.Addr().String()}, + }) + t.Cleanup(client.ForceStop) + ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) + defer cancel() + if err := client.Start(ctx); err != nil { + t.Fatal("start:", err) + } + session, collected := createRetirementHookSession(t, ctx, client) + client.ForceStop() + awaitRetirementCapture(t, collected) + runtime.KeepAlive(session) +} + +func TestForceStopRejectsAcknowledgedPlainResponseWaits(t *testing.T) { + for _, count := range []int{1, 2} { + for _, blockedHandler := range []bool{false, true} { + t.Run(fmt.Sprintf("%d waits/blocked handler=%t", count, blockedHandler), func(t *testing.T) { + t.Parallel() + peer := newResponseRetirementPeer(t, count) + client := copilot.NewClient(&copilot.ClientOptions{ + Connection: copilot.URIConnection{URL: peer.listener.Addr().String()}, + }) + t.Cleanup(client.ForceStop) + operationCtx, cancelOperation := context.WithTimeout(t.Context(), 10*time.Second) + defer cancelOperation() + if err := client.Start(operationCtx); err != nil { + t.Fatal("start:", err) + } + + session, err := client.CreateSession(operationCtx, &copilot.SessionConfig{ + SessionID: "retirement-session", OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + }) + if err != nil { + t.Fatal("create session:", err) + } + + entered := make(chan struct{}) + release := make(chan struct{}) + releaseHandler := sync.OnceFunc(func() { close(release) }) + t.Cleanup(releaseHandler) + if blockedHandler { + session.On(func(copilot.SessionEvent) { + close(entered) + <-release + }) + } + waitCtx, cancelWait := context.WithCancel(t.Context()) + results := make(chan error, count) + var waits sync.WaitGroup + t.Cleanup(func() { + cancelWait() + releaseHandler() + waits.Wait() + }) + for range count { + waits.Add(1) + go func() { + defer waits.Done() + _, err := session.SendAndWait(waitCtx, copilot.MessageOptions{Prompt: "hold the response"}) + results <- err + }() + } + select { + case <-peer.sent: + case <-operationCtx.Done(): + t.Fatal("send acknowledgments:", operationCtx.Err()) + } + // This later reply proves every preceding send acknowledgment reached the transport. + if _, err := client.Ping(operationCtx, "barrier"); err != nil { + t.Fatal("ping:", err) + } + if blockedHandler { + err := peer.write(map[string]any{ + "jsonrpc": "2.0", "method": "session.event", + "params": map[string]any{ + "sessionId": session.SessionID, + "event": map[string]any{ + "id": "00000000-0000-4000-8000-000000000001", "parentId": nil, + "timestamp": "2026-01-01T00:00:00Z", "type": "session.idle", + "ephemeral": true, "data": map[string]any{}, + }, + }, + }) + if err != nil { + t.Fatal("notify:", err) + } + select { + case <-entered: + case <-operationCtx.Done(): + t.Fatal("event handler did not enter:", operationCtx.Err()) + } + } + stopped := make(chan struct{}) + go func() { + client.ForceStop() + close(stopped) + }() + select { + case <-stopped: + case <-operationCtx.Done(): + t.Fatal("force stop joined the admitted handler:", operationCtx.Err()) + } + for range count { + select { + case err := <-results: + if err == nil || !strings.Contains(err.Error(), "session closed before response completed") { + t.Fatalf("expected response retirement error, got %v", err) + } + case <-time.After(5 * time.Second): + t.Fatal("acknowledged response wait remained blocked after force stop") + } + } + }) + } + } +} diff --git a/go/host.go b/go/host.go index 0abdd5dc15..7a75d0d7fb 100644 --- a/go/host.go +++ b/go/host.go @@ -41,6 +41,9 @@ type AhpSessionResumeRequest struct { // At least one transport must be supplied. Both may be enabled. // Experimental: AHP hosting may change or be removed. type AhpHostOptions struct { + // ComputeID selects a durable catalog identity; defaults are runtime-owned. + // It must agree with GitHubEnvironment.ComputeID when both are supplied. + ComputeID *string // LocalServer explicitly enables the local WebSocket listener. LocalServer *rpc.HostLocalServerOptions // GitHubEnvironment registers the host with Mission Control; Name and ComputeID are required. @@ -73,12 +76,17 @@ func (h *AhpHost) Dispose(ctx context.Context) error { return err } -// PublishSession exposes the exact resident session attached to the owning client. +// PublishSession durably advertises the exact attached session in the compute-scoped catalog. // It does not invoke factories or transfer ownership. func (h *AhpHost) PublishSession(ctx context.Context, sessionID string) (*rpc.HostPublishSessionResult, error) { return h.rpc.PublishSession(ctx, &rpc.HostPublishSessionRequest{HostID: h.HostID, SessionID: sessionID}) } +// ListSessions returns all live and dormant catalog sessions advertised by this host. +func (h *AhpHost) ListSessions(ctx context.Context) (*rpc.HostListSessionsResult, error) { + return h.rpc.ListSessions(ctx, &rpc.HostListSessionsRequest{HostID: &h.HostID}) +} + type ahpHostState struct { mu sync.Mutex hosts map[string]AhpHostOptions @@ -129,7 +137,7 @@ func (c *Client) StartAhpHost(ctx context.Context, options *AhpHostOptions) (*Ah c.ahp.hosts[hostID] = opts c.ahp.mu.Unlock() params := &rpc.HostStartRequest{ - HostID: hostID, LocalServer: opts.LocalServer, + HostID: hostID, ComputeID: opts.ComputeID, LocalServer: opts.LocalServer, GitHubEnvironment: opts.GitHubEnvironment, } if opts.CreateSession != nil { diff --git a/go/host_test.go b/go/host_test.go index c660b9b3ea..a6450f0904 100644 --- a/go/host_test.go +++ b/go/host_test.go @@ -47,8 +47,8 @@ func TestAhpHostTransportsAndOptionalResults(t *testing.T) { for _, transport := range []string{"local", "github", "both"} { t.Run(transport, func(t *testing.T) { client, server, _ := ahpFixture(t) - options := &AhpHostOptions{} - want := map[string]any{} + options := &AhpHostOptions{ComputeID: String("compute")} + want := map[string]any{"computeId": "compute"} if transport != "github" { port := int32(0) options.LocalServer = &rpc.HostLocalServerOptions{ @@ -111,6 +111,27 @@ func TestAhpHostTransportsAndOptionalResults(t *testing.T) { } } +func TestAhpHostListSessionsUsesOwningHost(t *testing.T) { + client, server, _ := ahpFixture(t) + host, err := client.StartAhpHost(t.Context(), &AhpHostOptions{LocalServer: &rpc.HostLocalServerOptions{}}) + if err != nil { + t.Fatal(err) + } + server.SetRequestHandler("host.listSessions", jsonrpc2.RequestHandlerFor(func(params *rpc.HostListSessionsRequest) (*rpc.HostListSessionsResult, *jsonrpc2.Error) { + if params.HostID == nil || *params.HostID != host.HostID { + t.Errorf("hostId = %v, want %q", params.HostID, host.HostID) + } + return &rpc.HostListSessionsResult{Sessions: []rpc.HostSessionSummary{}}, nil + })) + result, err := host.ListSessions(t.Context()) + if err != nil { + t.Fatal(err) + } + if result.Sessions == nil || len(result.Sessions) != 0 { + t.Fatalf("sessions = %#v, want an empty catalog", result.Sessions) + } +} + func TestAhpFactoryCancellationLogging(t *testing.T) { output := new(ahpTestLog) previous := log.Writer() diff --git a/go/image_generation_test.go b/go/image_generation_test.go new file mode 100644 index 0000000000..1c6586692c --- /dev/null +++ b/go/image_generation_test.go @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package copilot + +import ( + "encoding/json" + "testing" +) + +func TestImageGenerationSerialization(t *testing.T) { + for _, enabled := range []*bool{Bool(true), Bool(false), nil} { + var config *ImageGenerationConfig + if enabled != nil { + config = &ImageGenerationConfig{Enabled: enabled} + } + for _, request := range []any{ + createSessionRequest{ImageGeneration: config}, + resumeSessionRequest{SessionID: "image-test", ImageGeneration: config}, + } { + data, err := json.Marshal(request) + if err != nil { + t.Fatal(err) + } + var payload map[string]json.RawMessage + if err := json.Unmarshal(data, &payload); err != nil { + t.Fatal(err) + } + value, present := payload["imageGeneration"] + if enabled == nil { + if present { + t.Fatalf("expected omitted imageGeneration, got %s", data) + } + } else { + expected, err := json.Marshal(map[string]bool{"enabled": *enabled}) + if err != nil { + t.Fatal(err) + } + if string(value) != string(expected) { + t.Fatalf("imageGeneration = %s, want %s", value, expected) + } + } + } + } + data, err := json.Marshal(ImageGenerationConfig{}) + if err != nil || string(data) != "{}" { + t.Fatalf("unset enabled = %s, err = %v", data, err) + } +} diff --git a/go/internal/e2e/client_options_e2e_test.go b/go/internal/e2e/client_options_e2e_test.go index 739f1a58da..49294ca052 100644 --- a/go/internal/e2e/client_options_e2e_test.go +++ b/go/internal/e2e/client_options_e2e_test.go @@ -412,6 +412,7 @@ func TestClientOptionsE2E(t *testing.T) { extensionSDKPath := filepath.Join(ctx.WorkDir, "extension-sdk") session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ SessionID: sessionID, + Name: "go named at create", ClientName: "go-sdk-e2e-client", Model: "claude-sonnet-5", ReasoningEffort: "low", @@ -471,6 +472,7 @@ func TestClientOptionsE2E(t *testing.T) { } expectedValues := map[string]any{ "sessionId": sessionID, + "name": "go named at create", "clientName": "go-sdk-e2e-client", "model": "claude-sonnet-5", "reasoningEffort": "low", diff --git a/go/internal/e2e/runtime_host_e2e_test.go b/go/internal/e2e/runtime_host_e2e_test.go index b30325ca72..8f1ae6c4b7 100644 --- a/go/internal/e2e/runtime_host_e2e_test.go +++ b/go/internal/e2e/runtime_host_e2e_test.go @@ -72,6 +72,8 @@ type ahpApplication struct { session atomic.Pointer[copilot.Session] creates atomic.Int32 resumes atomic.Int32 + createID atomic.Value + resumeID atomic.Value tools atomic.Int32 hooks atomic.Int32 released chan *copilot.Session @@ -122,13 +124,21 @@ func (a *ahpApplication) options() *copilot.AhpHostOptions { if ctx.Err() != nil || request.Config.WorkingDirectory != a.workDir { return nil, fmt.Errorf("invalid create handoff") } + if request.Config.SessionID == "" { + return nil, fmt.Errorf("create handoff omitted runtime session identity") + } + a.createID.Store(request.Config.SessionID) a.createConfig(request.Config) session, err := a.client.CreateSession(ctx, request.Config) + if err == nil && session.SessionID != request.Config.SessionID { + return nil, fmt.Errorf("create returned %q, requested %q", session.SessionID, request.Config.SessionID) + } a.session.Store(session) return session, err }, ResumeSession: func(ctx context.Context, request copilot.AhpSessionResumeRequest) (*copilot.Session, error) { a.resumes.Add(1) + a.resumeID.Store(request.SessionID) config := request.Config if ctx.Err() != nil || config.WorkingDirectory != a.workDir || config.ContinuePendingWork == nil || *config.ContinuePendingWork { @@ -138,6 +148,9 @@ func (a *ahpApplication) options() *copilot.AhpHostOptions { config.SystemMessage = &copilot.SystemMessageConfig{Mode: "append", Content: ahpPromptMarker} config.Tools, config.Hooks = a.callbacks() session, err := a.client.ResumeSessionWithOptions(ctx, request.SessionID, config) + if err == nil && session.SessionID != request.SessionID { + return nil, fmt.Errorf("resume returned %q, requested %q", session.SessionID, request.SessionID) + } a.session.Store(session) return session, err }, @@ -228,7 +241,8 @@ func TestRuntimeHostE2E(t *testing.T) { driveAhp(t, ahp, map[string]any{"op": "attach", "clientId": clientID, "sessionId": sessionID}) } else { sessionID = driveAhp(t, ahp, map[string]any{"op": "create", "clientId": clientID, "workDir": ctx.WorkDir}).SessionID - if app.creates.Load() != 1 || app.session.Load().SessionID != sessionID { + if app.creates.Load() != 1 || app.session.Load().SessionID != app.createID.Load() || + app.session.Load().SessionID == sessionID { t.Fatal("create callback did not materialize the requested identity") } } @@ -279,6 +293,10 @@ func TestRuntimeHostE2E(t *testing.T) { } clientID, closeFirst := connectAhpTest(t, ahp, host, "") sessionID := driveAhp(t, ahp, map[string]any{"op": "create", "clientId": clientID, "workDir": ctx.WorkDir, "clientTools": true}).SessionID + runtimeID := first.session.Load().SessionID + if first.creates.Load() != 1 || first.createID.Load() != runtimeID || runtimeID == sessionID { + t.Fatal("create callback did not preserve its distinct runtime session identity") + } answer := driveAhp(t, ahp, map[string]any{"op": "turn", "clientId": clientID, "sessionId": sessionID, "prompt": "What is 2+2?"}) if !strings.Contains(answer.Text, "4") { t.Fatal(answer.Text) @@ -310,7 +328,8 @@ func TestRuntimeHostE2E(t *testing.T) { t.Fatalf("lost durable history: %+v", history) } if resumed.creates.Load() != 0 || resumed.resumes.Load() != 1 || - resumed.session.Load() == first.session.Load() || resumed.session.Load().SessionID != sessionID { + resumed.resumeID.Load() != runtimeID || + resumed.session.Load() == first.session.Load() || resumed.session.Load().SessionID != runtimeID { t.Fatal("incorrect application resume callback or identity") } response := driveAhp(t, ahp, map[string]any{"op": "turn", "clientId": reconnected, "sessionId": sessionID, "prompt": ahpComposedPrompt, "clientTools": true}) diff --git a/go/internal/e2e/skill_provider_e2e_test.go b/go/internal/e2e/skill_provider_e2e_test.go new file mode 100644 index 0000000000..d6c2dc93fb --- /dev/null +++ b/go/internal/e2e/skill_provider_e2e_test.go @@ -0,0 +1,586 @@ +package e2e + +import ( + "context" + "encoding/json" + "errors" + "os" + "path/filepath" + "strings" + "sync" + "testing" + "time" + + copilot "github.com/github/copilot-sdk/go" + "github.com/github/copilot-sdk/go/internal/e2e/testharness" + "github.com/github/copilot-sdk/go/rpc" +) + +type providedSkill struct { + descriptor rpc.SkillProviderDescriptor + read func() (string, error) +} + +type testSkillProvider struct { + mu sync.Mutex + skills []providedSkill + calls []string +} + +func newTestSkillProvider(skills []providedSkill) *testSkillProvider { + return &testSkillProvider{skills: skills} +} + +func providedSkillWithMarkdown(name, description, markdown string) providedSkill { + return providedSkill{ + descriptor: rpc.SkillProviderDescriptor{Name: name, Description: description}, + read: func() (string, error) { return markdown, nil }, + } +} + +func (p *testSkillProvider) ListSkills(ctx context.Context) ([]rpc.SkillProviderDescriptor, error) { + p.mu.Lock() + defer p.mu.Unlock() + p.calls = append(p.calls, "list") + skills := make([]rpc.SkillProviderDescriptor, 0, len(p.skills)) + for _, skill := range p.skills { + skills = append(skills, skill.descriptor) + } + return skills, nil +} + +func (p *testSkillProvider) ReadSkill(ctx context.Context, name string) (string, error) { + p.mu.Lock() + defer p.mu.Unlock() + p.calls = append(p.calls, "read:"+name) + for _, skill := range p.skills { + if skill.descriptor.Name == name { + return skill.read() + } + } + return "", copilot.ErrSkillNotFound +} + +func (p *testSkillProvider) Calls() []string { + p.mu.Lock() + defer p.mu.Unlock() + calls := make([]string, len(p.calls)) + copy(calls, p.calls) + return calls +} + +func (p *testSkillProvider) Reads() []string { + calls := p.Calls() + reads := make([]string, 0, len(calls)) + for _, call := range calls { + if strings.HasPrefix(call, "read:") { + reads = append(reads, strings.TrimPrefix(call, "read:")) + } + } + return reads +} + +// blockingSkillProvider blocks ListSkills until its context is cancelled. +type blockingSkillProvider struct { + entered chan struct{} + cancelled chan struct{} + enterOnce sync.Once + cancelOnce sync.Once +} + +func newBlockingSkillProvider() *blockingSkillProvider { + return &blockingSkillProvider{entered: make(chan struct{}), cancelled: make(chan struct{})} +} + +func (p *blockingSkillProvider) ListSkills(ctx context.Context) ([]rpc.SkillProviderDescriptor, error) { + p.enterOnce.Do(func() { close(p.entered) }) + <-ctx.Done() + p.cancelOnce.Do(func() { close(p.cancelled) }) + return nil, ctx.Err() +} + +func (p *blockingSkillProvider) ReadSkill(context.Context, string) (string, error) { + return "", copilot.ErrSkillNotFound +} + +func TestSkillProviderE2E(t *testing.T) { + ctx := testharness.NewTestContext(t) + client := ctx.NewClient() + t.Cleanup(func() { client.ForceStop() }) + + t.Run("should load provider skill lazily through skill tool", func(t *testing.T) { + ctx.ConfigureForTest(t) + provider := newTestSkillProvider([]providedSkill{ + providedSkillWithMarkdown( + "provider-lookup", + "Reports the provider lookup verification word.", + "# Provider lookup\n\nThe verification word is TANGERINE_QUARTZ_19. Reply with it.\n", + ), + }) + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: provider, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + t.Cleanup(func() { _ = session.Disconnect() }) + + list, err := session.RPC.Skills.List(t.Context()) + if err != nil { + t.Fatalf("Skills.List failed: %v", err) + } + listed := findSkill(list, "provider-lookup") + if listed == nil { + t.Fatal("Expected provider-lookup skill to be listed") + } + if listed.Source != rpc.SkillSourceSDK || !listed.Enabled { + t.Fatalf("Expected provider-lookup source=sdk enabled=true, got %+v", listed) + } + if listed.Path != nil && *listed.Path != "" { + t.Fatalf("Expected provider-lookup path to be empty, got %q", *listed.Path) + } + if reads := provider.Reads(); len(reads) != 0 { + t.Fatalf("Provider reads before skill load = %v, want []", reads) + } + + message, err := session.SendAndWait(t.Context(), copilot.MessageOptions{ + Prompt: "Use the skill tool to load the provider-lookup skill, then reply with its verification word.", + }) + if err != nil { + t.Fatalf("SendAndWait failed: %v", err) + } + + assertEqualStrings(t, provider.Reads(), []string{"provider-lookup"}) + // Validate the final assistant response arrived (guards against truncated captures) + assertAssistantContains(t, message, "TANGERINE_QUARTZ_19") + }) + + t.Run("should load provider and file based skills together", func(t *testing.T) { + ctx.ConfigureForTest(t) + skillsDir := filepath.Join(ctx.WorkDir, "file-skills") + fileSkillDir := filepath.Join(skillsDir, "file-notes") + if err := os.MkdirAll(fileSkillDir, 0755); err != nil { + t.Fatalf("MkdirAll failed: %v", err) + } + if err := os.WriteFile( + filepath.Join(fileSkillDir, "SKILL.md"), + []byte("---\nname: file-notes\ndescription: Reports the file notes verification word.\n---\n\nThe file notes verification word is MAPLE_FALCON_27.\n"), + 0644, + ); err != nil { + t.Fatalf("WriteFile failed: %v", err) + } + provider := newTestSkillProvider([]providedSkill{ + providedSkillWithMarkdown( + "provider-audit", + "Reports the provider audit verification word.", + "---\nname: provider-audit\nallowed-tools: view\n---\n\nThe provider audit verification word is COBALT_HERON_58.\n", + ), + }) + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillDirectories: []string{skillsDir}, + SkillProvider: provider, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + t.Cleanup(func() { _ = session.Disconnect() }) + + list, err := session.RPC.Skills.List(t.Context()) + if err != nil { + t.Fatalf("Skills.List failed: %v", err) + } + fileSkill := findSkill(list, "file-notes") + providerSkill := findSkill(list, "provider-audit") + if fileSkill == nil || fileSkill.Source == rpc.SkillSourceSDK || fileSkill.Path == nil || *fileSkill.Path == "" { + t.Fatalf("Unexpected file-notes skill: %+v", fileSkill) + } + if providerSkill == nil || providerSkill.Source != rpc.SkillSourceSDK { + t.Fatalf("Unexpected provider-audit skill: %+v", providerSkill) + } + + message, err := session.SendAndWait(t.Context(), copilot.MessageOptions{ + Prompt: "Use the skill tool to load the file-notes skill and the provider-audit skill, then reply with both verification words.", + }) + if err != nil { + t.Fatalf("SendAndWait failed: %v", err) + } + + assertEqualStrings(t, provider.Reads(), []string{"provider-audit"}) + assertAssistantContains(t, message, "MAPLE_FALCON_27") + // Validate the final assistant response arrived (guards against truncated captures) + assertAssistantContains(t, message, "COBALT_HERON_58") + }) + + t.Run("should rebind skill provider on resume", func(t *testing.T) { + ctx.ConfigureForTest(t) + original := newTestSkillProvider([]providedSkill{ + providedSkillWithMarkdown( + "rebind-check", + "Reports the rebind verification word.", + "The rebind verification word is AMBER_ALPHA_11.\n", + ), + }) + replacement := newTestSkillProvider([]providedSkill{ + providedSkillWithMarkdown( + "rebind-check", + "Reports the rebind verification word.", + "The rebind verification word is BRONZE_BETA_22.\n", + ), + }) + first, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: original, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + sessionID := first.SessionID + if _, err := first.SendAndWait(t.Context(), copilot.MessageOptions{ + Prompt: "Without using any tools or skills, reply with exactly REBIND_READY.", + }); err != nil { + t.Fatalf("Initial SendAndWait failed: %v", err) + } + if err := first.Disconnect(); err != nil { + t.Fatalf("Disconnect failed: %v", err) + } + if reads := original.Reads(); len(reads) != 0 { + t.Fatalf("Original provider reads before resume = %v, want []", reads) + } + originalCallsBeforeResume := len(original.Calls()) + + session, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: replacement, + }) + if err != nil { + t.Fatalf("ResumeSession failed: %v", err) + } + t.Cleanup(func() { _ = session.Disconnect() }) + + message, err := session.SendAndWait(t.Context(), copilot.MessageOptions{ + Prompt: "Use the skill tool to load the rebind-check skill, then reply with its verification word.", + }) + if err != nil { + t.Fatalf("SendAndWait failed: %v", err) + } + + assertEqualStrings(t, replacement.Reads(), []string{"rebind-check"}) + if got := len(original.Calls()); got != originalCallsBeforeResume { + t.Fatalf("Original provider call count after resume = %d, want %d", got, originalCallsBeforeResume) + } + // Validate the final assistant response arrived (guards against truncated captures) + assertAssistantContains(t, message, "BRONZE_BETA_22") + assertAssistantNotContains(t, message, "AMBER_ALPHA_11") + }) + + t.Run("should report provider read failure without leaking details", func(t *testing.T) { + ctx.ConfigureForTest(t) + secret := "PROVIDER_SECRET_7F3A9C" + provider := newTestSkillProvider([]providedSkill{ + { + descriptor: rpc.SkillProviderDescriptor{ + Name: "broken-lookup", + Description: "Reports the broken lookup verification word.", + }, + read: func() (string, error) { + return "", errors.New("database unavailable: " + secret) + }, + }, + }) + events := newEventRecorder() + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: provider, + OnEvent: events.Record, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + t.Cleanup(func() { _ = session.Disconnect() }) + + message, err := session.SendAndWait(t.Context(), copilot.MessageOptions{ + Prompt: "Use the skill tool to load the broken-lookup skill. If loading fails, reply with exactly LOAD_FAILED.", + }) + if err != nil { + t.Fatalf("SendAndWait failed: %v", err) + } + + assertContainsString(t, provider.Reads(), "broken-lookup") + failures := failedToolCompletions(events.Snapshot()) + if len(failures) != 1 { + t.Fatalf("Expected exactly 1 failed tool completion, got %d", len(failures)) + } + rawEvents, err := json.Marshal(events.Snapshot()) + if err != nil { + t.Fatalf("Marshal events failed: %v", err) + } + if strings.Contains(string(rawEvents), secret) { + t.Fatalf("Provider error leaked secret in events: %s", rawEvents) + } + // Validate the final assistant response arrived (guards against truncated captures) + assertAssistantContains(t, message, "LOAD_FAILED") + }) + + t.Run("should report missing provider skill as not found", func(t *testing.T) { + ctx.ConfigureForTest(t) + provider := newTestSkillProvider([]providedSkill{ + { + descriptor: rpc.SkillProviderDescriptor{ + Name: "vanished-lookup", + Description: "Reports the vanished lookup verification word.", + }, + read: func() (string, error) { + return "", copilot.ErrSkillNotFound + }, + }, + }) + events := newEventRecorder() + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: provider, + OnEvent: events.Record, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + t.Cleanup(func() { _ = session.Disconnect() }) + + message, err := session.SendAndWait(t.Context(), copilot.MessageOptions{ + Prompt: "Use the skill tool to load the vanished-lookup skill. If loading fails, reply with exactly LOAD_FAILED.", + }) + if err != nil { + t.Fatalf("SendAndWait failed: %v", err) + } + + assertContainsString(t, provider.Reads(), "vanished-lookup") + failures := failedToolCompletions(events.Snapshot()) + if len(failures) != 1 { + t.Fatalf("Expected exactly 1 failed tool completion, got %d", len(failures)) + } + rawFailure, err := json.Marshal(failures[0]) + if err != nil { + t.Fatalf("Marshal failure failed: %v", err) + } + if !strings.Contains(strings.ToLower(string(rawFailure)), "not found") { + t.Fatalf("Expected failure to mention not found, got %s", rawFailure) + } + // Validate the final assistant response arrived (guards against truncated captures) + assertAssistantContains(t, message, "LOAD_FAILED") + }) + + t.Run("should keep provider dormant when skills disabled", func(t *testing.T) { + ctx.ConfigureWithoutSnapshot(t) + provider := newTestSkillProvider([]providedSkill{ + providedSkillWithMarkdown("dormant-lookup", "Never listed.", "Never read.\n"), + }) + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + EnableSkills: copilot.Bool(false), + SkillProvider: provider, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + t.Cleanup(func() { _ = session.Disconnect() }) + + if _, err := session.RPC.Skills.EnsureLoaded(t.Context()); err != nil { + t.Fatalf("Skills.EnsureLoaded failed: %v", err) + } + list, err := session.RPC.Skills.List(t.Context()) + if err != nil { + t.Fatalf("Skills.List failed: %v", err) + } + if sdkSkills := sdkSkills(list); len(sdkSkills) != 0 { + t.Fatalf("Expected no sdk skills when disabled, got %+v", sdkSkills) + } + if calls := provider.Calls(); len(calls) != 0 { + t.Fatalf("Provider calls when skills disabled = %v, want []", calls) + } + }) + + t.Run("should unbind provider when resumed without one", func(t *testing.T) { + ctx.ConfigureWithoutSnapshot(t) + provider := newTestSkillProvider([]providedSkill{ + providedSkillWithMarkdown("unbound-lookup", "Reports the unbound lookup word.", "Unbound.\n"), + }) + first, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: provider, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + before, err := first.RPC.Skills.List(t.Context()) + if err != nil { + t.Fatalf("Skills.List before resume failed: %v", err) + } + if findSkill(before, "unbound-lookup") == nil { + t.Fatal("Expected unbound-lookup before resume") + } + callsBeforeResume := len(provider.Calls()) + + session, err := client.ResumeSession(t.Context(), first.SessionID, &copilot.ResumeSessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + }) + if err != nil { + t.Fatalf("ResumeSession failed: %v", err) + } + t.Cleanup(func() { _ = session.Disconnect() }) + + if _, err := session.RPC.Skills.Reload(t.Context()); err != nil { + t.Fatalf("Skills.Reload failed: %v", err) + } + list, err := session.RPC.Skills.List(t.Context()) + if err != nil { + t.Fatalf("Skills.List after resume failed: %v", err) + } + if sdkSkills := sdkSkills(list); len(sdkSkills) != 0 { + t.Fatalf("Expected no sdk skills after unbound resume, got %+v", sdkSkills) + } + if got := len(provider.Calls()); got != callsBeforeResume { + t.Fatalf("Provider call count after unbound resume = %d, want %d", got, callsBeforeResume) + } + }) + + t.Run("should cancel a blocked provider call when the session disconnects", func(t *testing.T) { + ctx.ConfigureWithoutSnapshot(t) + provider := newBlockingSkillProvider() + session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + SkillProvider: provider, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + + // The list RPC fails once the binding is removed; only the provider's + // cancellation matters here. + go func() { _, _ = session.RPC.Skills.List(context.Background()) }() + select { + case <-provider.entered: + case <-time.After(30 * time.Second): + t.Fatal("provider ListSkills was not called") + } + + if err := session.Disconnect(); err != nil { + t.Fatalf("Disconnect failed: %v", err) + } + select { + case <-provider.cancelled: + case <-time.After(10 * time.Second): + t.Fatal("provider context was not cancelled after Disconnect") + } + }) + + t.Run("should reject skill provider for cloud sessions", func(t *testing.T) { + ctx.ConfigureWithoutSnapshot(t) + provider := newTestSkillProvider([]providedSkill{ + providedSkillWithMarkdown("cloud-lookup", "Never listed.", "Never read.\n"), + }) + + _, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ + OnPermissionRequest: copilot.PermissionHandler.ApproveAll, + Cloud: &copilot.CloudSessionOptions{}, + SkillProvider: provider, + }) + if err == nil || err.Error() != "Skill providers are not supported for cloud sessions." { + t.Fatalf("CreateSession error = %v, want cloud skill provider rejection", err) + } + if calls := provider.Calls(); len(calls) != 0 { + t.Fatalf("Provider calls after cloud rejection = %v, want []", calls) + } + }) +} + +type eventRecorder struct { + mu sync.Mutex + events []copilot.SessionEvent +} + +func newEventRecorder() *eventRecorder { + return &eventRecorder{} +} + +func (r *eventRecorder) Record(event copilot.SessionEvent) { + r.mu.Lock() + defer r.mu.Unlock() + r.events = append(r.events, event) +} + +func (r *eventRecorder) Snapshot() []copilot.SessionEvent { + r.mu.Lock() + defer r.mu.Unlock() + events := make([]copilot.SessionEvent, len(r.events)) + copy(events, r.events) + return events +} + +func findSkill(list *rpc.SkillList, name string) *rpc.Skill { + if list == nil { + return nil + } + for i := range list.Skills { + if list.Skills[i].Name == name { + return &list.Skills[i] + } + } + return nil +} + +func sdkSkills(list *rpc.SkillList) []rpc.Skill { + if list == nil { + return nil + } + var matches []rpc.Skill + for _, skill := range list.Skills { + if skill.Source == rpc.SkillSourceSDK { + matches = append(matches, skill) + } + } + return matches +} + +func failedToolCompletions(events []copilot.SessionEvent) []*copilot.ToolExecutionCompleteData { + var failures []*copilot.ToolExecutionCompleteData + for _, event := range events { + if data, ok := event.Data.(*copilot.ToolExecutionCompleteData); ok && !data.Success { + failures = append(failures, data) + } + } + return failures +} + +func assertAssistantNotContains(t *testing.T, event *copilot.SessionEvent, text string) { + t.Helper() + data, ok := event.Data.(*copilot.AssistantMessageData) + if !ok { + t.Fatalf("Expected AssistantMessageData, got %T", event.Data) + } + if strings.Contains(data.Content, text) { + t.Fatalf("Expected assistant response not to contain %q, got %q", text, data.Content) + } +} + +func assertEqualStrings(t *testing.T, got, want []string) { + t.Helper() + if len(got) != len(want) { + t.Fatalf("strings = %v, want %v", got, want) + } + for i := range got { + if got[i] != want[i] { + t.Fatalf("strings = %v, want %v", got, want) + } + } +} + +func assertContainsString(t *testing.T, got []string, want string) { + t.Helper() + for _, value := range got { + if value == want { + return + } + } + t.Fatalf("strings = %v, want to contain %q", got, want) +} diff --git a/go/internal/jsonrpc2/jsonrpc2.go b/go/internal/jsonrpc2/jsonrpc2.go index d4898b6a9c..14566f7bea 100644 --- a/go/internal/jsonrpc2/jsonrpc2.go +++ b/go/internal/jsonrpc2/jsonrpc2.go @@ -329,11 +329,11 @@ func (c *Client) RequestWithInlineResponse(ctx context.Context, method string, p return response.Result, nil case <-c.processDone: if err := c.getProcessError(); err != nil { - return nil, err + return responseAfterShutdown(responseChan, err) } - return nil, fmt.Errorf("process exited unexpectedly") + return responseAfterShutdown(responseChan, fmt.Errorf("process exited unexpectedly")) case <-c.stopChan: - return nil, fmt.Errorf("client stopped") + return responseAfterShutdown(responseChan, fmt.Errorf("client stopped")) } } select { @@ -345,9 +345,22 @@ func (c *Client) RequestWithInlineResponse(ctx context.Context, method string, p } return response.Result, nil case <-c.connectionClosed: - return nil, fmt.Errorf("connection closed") + return responseAfterShutdown(responseChan, fmt.Errorf("connection closed")) case <-c.stopChan: - return nil, fmt.Errorf("client stopped") + return responseAfterShutdown(responseChan, fmt.Errorf("client stopped")) + } +} + +func responseAfterShutdown(responseChan <-chan *Response, shutdownErr error) (json.RawMessage, error) { + // Shutdown can win the outer select after the read loop has already admitted a reply. + select { + case response := <-responseChan: + if response.Error != nil { + return nil, response.Error + } + return response.Result, nil + default: + return nil, shutdownErr } } diff --git a/go/internal/jsonrpc2/jsonrpc2_test.go b/go/internal/jsonrpc2/jsonrpc2_test.go index 258992e101..0c42f185aa 100644 --- a/go/internal/jsonrpc2/jsonrpc2_test.go +++ b/go/internal/jsonrpc2/jsonrpc2_test.go @@ -3,7 +3,9 @@ package jsonrpc2 import ( "bytes" "context" + "encoding/json" "errors" + "fmt" "io" "sync" "testing" @@ -16,6 +18,10 @@ type writeCloser struct { func (w writeCloser) Close() error { return nil } +type writeFunc func([]byte) (int, error) + +func (w writeFunc) Write(data []byte) (int, error) { return w(data) } + func TestOnCloseCalledOnUnexpectedExit(t *testing.T) { stdinR, stdinW := io.Pipe() stdoutR, stdoutW := io.Pipe() @@ -110,6 +116,135 @@ func TestRequestReturnsWhenConnectionCloses(t *testing.T) { } } +func TestRequestUnacknowledgedShutdown(t *testing.T) { + for _, shutdown := range []string{"stop", "connection closed", "process exited", "process error"} { + t.Run(shutdown, func(t *testing.T) { + stdinR, stdinW := io.Pipe() + defer stdinR.Close() + defer stdinW.Close() + client := NewClient(stdinW, io.NopCloser(bytes.NewReader(nil))) + done := make(chan struct{}) + var processErr error + if shutdown == "process error" { + processErr = errors.New("CLI process exited: exit status 1") + } + if shutdown == "process exited" || shutdown == "process error" { + client.SetProcessDone(done, &processErr) + } + ctx, cancel := context.WithCancel(t.Context()) + finished := make(chan struct{}) + t.Cleanup(func() { + cancel() + stdinR.Close() + select { + case <-finished: + case <-time.After(time.Second): + t.Error("request did not finish during cleanup") + } + }) + result := make(chan error, 1) + go func() { + defer close(finished) + _, err := client.Request(ctx, "test.method", nil) + result <- err + }() + if _, err := newHeaderReader(stdinR).Read(); err != nil { + t.Fatalf("Read request failed: %v", err) + } + var expected string + switch shutdown { + case "stop": + close(client.stopChan) + expected = "client stopped" + case "connection closed": + close(client.connectionClosed) + expected = "connection closed" + case "process exited": + close(done) + expected = "process exited unexpectedly" + case "process error": + close(done) + expected = processErr.Error() + } + select { + case err := <-result: + if err == nil || err.Error() != expected { + t.Fatalf("unacknowledged request error = %v, want %s", err, expected) + } + case <-time.After(time.Second): + t.Fatal("unacknowledged request did not stop") + } + client.mu.Lock() + pending, callbacks := len(client.pendingRequests), len(client.pendingInlineCallbacks) + client.mu.Unlock() + if pending != 0 || callbacks != 0 { + t.Fatalf("request cleanup left %d pending requests and %d callbacks", pending, callbacks) + } + }) + } +} + +func TestRequestAdmittedResponseSurvivesShutdown(t *testing.T) { + for _, shutdown := range []string{"stop", "connection closed", "process exited", "process error"} { + t.Run(shutdown, func(t *testing.T) { + for _, rpcError := range []bool{false, true} { + for iteration := range 32 { + t.Run(fmt.Sprintf("RPC_error=%t/%d", rpcError, iteration), func(t *testing.T) { + expected := json.RawMessage(`{"messageId":"acknowledged-message"}`) + var expectedErr *Error + if rpcError { + expectedErr = &Error{Code: -32001, Message: "acknowledged failure", Data: json.RawMessage(`{"detail":"original"}`)} + } + done := make(chan struct{}) + var client *Client + writer := writeFunc(func(data []byte) (int, error) { + if bytes.HasPrefix(data, []byte("Content-Length:")) { + return len(data), nil + } + var request Request + if err := json.Unmarshal(data, &request); err != nil { + return 0, err + } + // Both outcomes are ready before Request reaches its response select. + client.handleResponse(&Response{ID: request.ID, Result: expected, Error: expectedErr}) + switch shutdown { + case "stop": + close(client.stopChan) + case "connection closed": + close(client.connectionClosed) + default: + close(done) + } + return len(data), nil + }) + client = NewClient(writeCloser{Writer: writer}, io.NopCloser(bytes.NewReader(nil))) + if shutdown == "process exited" || shutdown == "process error" { + var processErr error + if shutdown == "process error" { + processErr = errors.New("CLI process exited: exit status 1") + } + client.SetProcessDone(done, &processErr) + } + + result, err := client.Request(t.Context(), "test.method", nil) + + if expectedErr != nil { + if result != nil || err != expectedErr { + t.Fatalf("admitted error = (%s, %v), want original RPC error %v", result, err, expectedErr) + } + } else if err != nil || !bytes.Equal(result, expected) { + t.Fatalf("admitted response = (%s, %v), want (%s, nil)", result, err, expected) + } + if len(client.pendingRequests) != 0 || len(client.pendingInlineCallbacks) != 0 { + t.Fatal("completed request retained its pending response or callback") + } + }) + } + } + }) + } +} + // TestSetProcessDone_ErrorAvailableImmediately validates that getProcessError() // returns the correct error immediately after processDone is closed. // The current implementation stores a pointer to the process error diff --git a/go/rpc/mcp_list_test.go b/go/rpc/mcp_list_test.go new file mode 100644 index 0000000000..7a2f3e0427 --- /dev/null +++ b/go/rpc/mcp_list_test.go @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package rpc + +import ( + "context" + "encoding/json" + "io" + "testing" + + "github.com/github/copilot-sdk/go/internal/jsonrpc2" +) + +var _ interface { + List(context.Context) (*MCPServerList, error) + ListConfigured(context.Context) (*MCPConfiguredServerList, error) +} = (*MCPAPI)(nil) + +func TestMCPListUsesParameterlessWireContract(t *testing.T) { + clientToServerReader, clientToServerWriter := io.Pipe() + serverToClientReader, serverToClientWriter := io.Pipe() + client := jsonrpc2.NewClient(clientToServerWriter, serverToClientReader) + server := jsonrpc2.NewClient(serverToClientWriter, clientToServerReader) + requests := make(chan map[string]any, 2) + server.SetRequestHandler("session.mcp.list", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request map[string]any + if err := json.Unmarshal(params, &request); err != nil { + return nil, &jsonrpc2.Error{Code: -32602, Message: err.Error()} + } + requests <- request + return json.RawMessage(`{"servers":[]}`), nil + }) + server.SetRequestHandler("session.mcp.listConfigured", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + var request map[string]any + if err := json.Unmarshal(params, &request); err != nil { + return nil, &jsonrpc2.Error{Code: -32602, Message: err.Error()} + } + requests <- request + return json.RawMessage(`{"servers":[ + {"name":"cold","enabled":true,"live":{"status":"not_configured"}}, + {"name":"old-connection","enabled":false,"live":{"status":"connected"}}, + {"name":"auth","enabled":true,"live":{"status":"needs-auth"}}, + {"name":"stopped","enabled":true,"live":{"status":"stopped"}}, + {"name":"failed","enabled":true,"live":{"status":"failed","error":"connection failed"}} + ]}`), nil + }) + client.Start() + server.Start() + t.Cleanup(func() { + client.Stop() + server.Stop() + _ = clientToServerWriter.Close() + _ = clientToServerReader.Close() + _ = serverToClientWriter.Close() + _ = serverToClientReader.Close() + }) + + mcp := NewSessionRPC(client, "session-1").MCP + if _, err := mcp.List(t.Context()); err != nil { + t.Fatal(err) + } + configured, err := mcp.ListConfigured(t.Context()) + if err != nil { + t.Fatal(err) + } + want := []MCPServerStatus{"not_configured", "connected", "needs-auth", "stopped", "failed"} + if len(configured.Servers) != len(want) { + t.Fatalf("configured servers = %#v, want %d entries", configured.Servers, len(want)) + } + for i, status := range want { + live := configured.Servers[i].Live + if live.Status != status { + t.Fatalf("live status = %q, want %q", live.Status, status) + } + } + if configured.Servers[1].Enabled || configured.Servers[4].Live.Error == nil || + *configured.Servers[4].Live.Error != "connection failed" { + t.Fatalf("configuration enablement and runtime error were not preserved: %#v", configured.Servers) + } + got := make([]map[string]any, 2) + for i := range got { + got[i] = <-requests + } + for _, request := range got { + if request["sessionId"] != "session-1" || len(request) != 1 { + t.Fatalf("request = %#v, want only the bound session ID", request) + } + } +} diff --git a/go/rpc/repo_settings_test.go b/go/rpc/repo_settings_test.go new file mode 100644 index 0000000000..529daa40ff --- /dev/null +++ b/go/rpc/repo_settings_test.go @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package rpc_test + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + + "github.com/github/copilot-sdk/go/rpc" +) + +func ExampleRepoSettingsReadRawResult() { + const input = `{"config":{"custom":{"items":[true,null,12.5]}},"invalid":false}` + var result rpc.RepoSettingsReadRawResult + if err := json.Unmarshal([]byte(input), &result); err != nil { + panic(err) + } + output, err := json.Marshal(result) + if err != nil { + panic(err) + } + fmt.Println(string(output)) + // Output: {"config":{"custom":{"items":[true,null,12.5]}},"invalid":false} +} + +func TestRawRepoSettingsPreserveUnknownJSON(t *testing.T) { + for _, input := range []string{ + `{"config":{"custom":{"items":[true,null,12.5],"text":"preserved"}},"invalid":false}`, + `{"config":{},"invalid":true}`, + } { + t.Run(input, func(t *testing.T) { + var decoded rpc.RepoSettingsReadRawResult + if err := json.Unmarshal([]byte(input), &decoded); err != nil { + t.Fatal(err) + } + output, err := json.Marshal(decoded) + if err != nil { + t.Fatal(err) + } + var expected, actual any + if err := json.Unmarshal([]byte(input), &expected); err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(output, &actual); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("repository settings changed:\nactual: %s\nexpected: %s", output, input) + } + }) + } +} diff --git a/go/rpc/settings_presence_test.go b/go/rpc/settings_presence_test.go new file mode 100644 index 0000000000..86c562e194 --- /dev/null +++ b/go/rpc/settings_presence_test.go @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package rpc + +import ( + "context" + "encoding/json" + "net" + "testing" + "time" + + "github.com/github/copilot-sdk/go/internal/jsonrpc2" +) + +func TestSettingsValuePresenceOnWire(t *testing.T) { + for _, method := range []string{"user.settings.applyTopKey", "repo.settings.writeKey", "user.settings.edit"} { + for _, test := range []struct { + name string + value any + present bool + delete bool + }{ + {name: "omitted"}, + {name: "explicit null", value: json.RawMessage("null"), present: true}, + {name: "value", value: "chosen", present: true}, + {name: "delete", delete: true}, + } { + t.Run(method+"/"+test.name, func(t *testing.T) { + clientConn, serverConn := net.Pipe() + defer clientConn.Close() + defer serverConn.Close() + client := jsonrpc2.NewClient(clientConn, clientConn) + server := jsonrpc2.NewClient(serverConn, serverConn) + requests := make(chan json.RawMessage, 1) + server.SetRequestHandler(method, func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + requests <- params + return json.RawMessage(`{}`), nil + }) + client.Start() + server.Start() + defer client.Stop() + defer server.Stop() + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + api := NewInternalServerRPC(client) + var err error + switch method { + case "user.settings.applyTopKey": + var value *any + if test.present { + value = &test.value + } + _, err = api.User.Settings().ApplyTopKey(ctx, &UserSettingsApplyTopKeyRequest{ + CanonicalPath: []string{"model"}, + TopKey: "model", + Value: value, + Delete: &test.delete, + }) + case "repo.settings.writeKey": + _, err = api.Repo.Settings().WriteKey(ctx, &RepoSettingsWriteKeyRequest{ + RepoRoot: t.TempDir(), + Scope: "repo", + Key: "model", + Value: test.value, + Delete: &test.delete, + }) + case "user.settings.edit": + operation := SettingsEditOperationSet + if test.delete { + operation = SettingsEditOperationRemove + } + _, err = api.User.Settings().Edit(ctx, &UserSettingsEditRequest{ + CanonicalPath: []string{"model"}, + Operation: operation, + Value: test.value, + }) + } + if err != nil { + t.Fatal(err) + } + select { + case raw := <-requests: + var fields map[string]json.RawMessage + if err := json.Unmarshal(raw, &fields); err != nil { + t.Fatal(err) + } + value, present := fields["value"] + wantPresent := test.present || (method == "user.settings.edit" && !test.delete) + if present != wantPresent { + t.Fatalf("value presence = %v, want %v; wire params: %s", present, wantPresent, raw) + } + if present { + expected, err := json.Marshal(test.value) + if err != nil { + t.Fatal(err) + } + if string(value) != string(expected) { + t.Fatalf("value = %s, want %s; wire params: %s", value, expected, raw) + } + } + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + }) + } + } +} diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index c0af9e58ab..cc7b86d136 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -39,6 +39,28 @@ type AccountAllUsers struct { Token *string `json:"token,omitempty"` } +// The authentication identity whose shared wording should be rendered. +// Experimental: AccountDescribeAuthInfoRequest is part of an experimental API and may +// change or be removed. +// Internal: AccountDescribeAuthInfoRequest is an internal SDK API and is not part of the +// public surface. +type AccountDescribeAuthInfoRequest struct { + // Identity to describe. + Identity AuthIdentity `json:"identity"` +} + +// The wording the runtime uses for an authentication identity. +// Experimental: AccountDescribeAuthInfoResult is part of an experimental API and may change +// or be removed. +// Internal: AccountDescribeAuthInfoResult is an internal SDK API and is not part of the +// public surface. +type AccountDescribeAuthInfoResult struct { + // One-line description of the identity, suitable after a verb such as "Switched to". + Description string `json:"description"` + // Sign-in banner announcing the authenticated user. + Message string `json:"message"` +} + // List of all authenticated users // Experimental: AccountGetAllUsersResult is part of an experimental API and may change or // be removed. @@ -54,6 +76,30 @@ type AccountGetCurrentAuthResult struct { AuthInfo AuthInfo `json:"authInfo,omitempty"` } +// The authentication identity whose gist support should be reported. +// Experimental: AccountGetGistSupportRequest is part of an experimental API and may change +// or be removed. +// Internal: AccountGetGistSupportRequest is an internal SDK API and is not part of the +// public surface. +type AccountGetGistSupportRequest struct { + // Identity to evaluate. + Identity AuthIdentity `json:"identity"` +} + +// Whether the identity can create gists, and why not when it cannot. +// Experimental: AccountGetGistSupportResult is part of an experimental API and may change +// or be removed. +// Internal: AccountGetGistSupportResult is an internal SDK API and is not part of the +// public surface. +type AccountGetGistSupportResult struct { + // Machine-readable reason category when unsupported. + Kind *string `json:"kind,omitempty"` + // Human-readable explanation to show where the gist action would have been. + Reason *string `json:"reason,omitempty"` + // True when the identity can create gists. + Supported bool `json:"supported"` +} + // Experimental: AccountGetQuotaRequest is part of an experimental API and may change or be // removed. type AccountGetQuotaRequest struct { @@ -73,6 +119,40 @@ type AccountGetQuotaResult struct { QuotaSnapshots map[string]AccountQuotaSnapshot `json:"quotaSnapshots"` } +// The environment variable supplying a classic personal access token, when one is set. +// Experimental: AccountGetTokenEnvVarResult is part of an experimental API and may change +// or be removed. +// Internal: AccountGetTokenEnvVarResult is an internal SDK API and is not part of the +// public surface. +type AccountGetTokenEnvVarResult struct { + // Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the + // environment. + Name *string `json:"name,omitempty"` +} + +// A path to resolve against the GitHub host an identity is signed in to. +// Experimental: AccountGetWebURLRequest is part of an experimental API and may change or be +// removed. +// Internal: AccountGetWebURLRequest is an internal SDK API and is not part of the public +// surface. +type AccountGetWebURLRequest struct { + // Identity whose host the path resolves against. Omit to resolve against the public + // github.com host. + Identity *AuthIdentity `json:"identity,omitempty"` + // Host-relative path, without a leading slash, for example `settings/copilot/features`. + Path string `json:"path"` +} + +// An absolute URL on the identity's GitHub host. +// Experimental: AccountGetWebURLResult is part of an experimental API and may change or be +// removed. +// Internal: AccountGetWebURLResult is an internal SDK API and is not part of the public +// surface. +type AccountGetWebURLResult struct { + // Absolute URL for the requested path. + URL string `json:"url"` +} + // Credentials to validate and store. Omit login to resolve the authenticated user from the // token. // Experimental: AccountLoginRequest is part of an experimental API and may change or be @@ -167,6 +247,9 @@ type AccountsSetRequest struct { type AccountStatus struct { // Whether this is the active account. Active bool `json:"active"` + // Human-readable credential source used to authenticate this account, such as `gh` or + // `GITHUB_TOKEN`. + AuthSource *string `json:"authSource,omitempty"` // Opaque id of the account this one was derived from (e.g. an EMU account's base Entra // identity); absent for a root account. Matches the base identity account's selectionId, // forming the derivation edge. @@ -223,6 +306,8 @@ type AgentInfo struct { DisableModelInvocation *bool `json:"disableModelInvocation,omitempty"` // Human-readable display name DisplayName string `json:"displayName"` + // Declarative hook actions keyed by event name, executed only while this agent is active. + Hooks map[string][]any `json:"hooks,omitzero"` // Stable identifier for selection. For most agents this is the same as `name`; for // plugin/builtin agents it may differ. Always populated; defaults to `name` when no // distinct id was assigned. @@ -468,10 +553,46 @@ type AgentReloadResult struct { Agents []AgentInfo `json:"agents"` } +// The models a custom agent asks for, and the models actually available. +// Experimental: AgentsCustomAgentInitialModelDecisionParams is part of an experimental API +// and may change or be removed. +// Internal: AgentsCustomAgentInitialModelDecisionParams is an internal SDK API and is not +// part of the public surface. +type AgentsCustomAgentInitialModelDecisionParams struct { + // The agent's declared `model:` entry, serialized. A single name or an ordered list of + // acceptable names. + AgentModelsJSON string `json:"agentModelsJson"` + // The models available to this session, serialized in the shape the model list carries. + AvailableModelsJSON string `json:"availableModelsJson"` +} + +// The model to switch to, and the warning to show when the agent's preference could not be +// met. +// Experimental: AgentsCustomAgentInitialModelDecisionResult is part of an experimental API +// and may change or be removed. +// Internal: AgentsCustomAgentInitialModelDecisionResult is an internal SDK API and is not +// part of the public surface. +type AgentsCustomAgentInitialModelDecisionResult struct { + // The reasoning effort attached to the selected model preference. Absent when that + // preference does not specify an effort. + ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // The first available model that matches the agent's preferences. Absent when none of the + // requested models is available. + TargetModel *string `json:"targetModel,omitempty"` + // What to tell the user about an unmet preference. Absent when the preference was met. A + // warning with no `targetModel` means the agent's models are all unavailable. + Warning *string `json:"warning,omitempty"` +} + // Optional project paths to include in agent discovery. // Experimental: AgentsDiscoverRequest is part of an experimental API and may change or be // removed. type AgentsDiscoverRequest struct { + // Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + // Available without ambient discovery, subject to managed/source disables. Relative paths + // resolve against the request's effective working directory when supplied. Null and + // omission are equivalent; an empty array contributes no explicit roots. + AgentDirectories []string `json:"agentDirectories,omitzero"` // When true, omit the host's agents (the user-level agent directory and all plugin agents), // leaving only project and remote agents. For multitenant deployments. ExcludeHostAgents *bool `json:"excludeHostAgents,omitempty"` @@ -506,10 +627,110 @@ type AgentSetPromptRequest struct { Prompt string `json:"prompt"` } +// The feature flags to evaluate shipped agents against. +// Experimental: AgentsGetAvailableBuiltinsRequest is part of an experimental API and may +// change or be removed. +// Internal: AgentsGetAvailableBuiltinsRequest is an internal SDK API and is not part of the +// public surface. +type AgentsGetAvailableBuiltinsRequest struct { + // The surface asking, which gates agents that only apply to one client. Omit or pass null + // to apply no client filter. + Context *string `json:"context,omitempty"` + // Feature flag values keyed by name, evaluated with the runtime's truthiness rules. Omit or + // pass null for no flags. + FeatureFlags map[string]any `json:"featureFlags,omitzero"` + // Flag overrides keyed by name. A null entry uses the corresponding base flag; false + // explicitly disables it. Omit or pass null for no overrides. + Overrides map[string]any `json:"overrides,omitzero"` +} + +// The shipped agents available under the requested flags. +// Experimental: AgentsGetAvailableBuiltinsResult is part of an experimental API and may +// change or be removed. +// Internal: AgentsGetAvailableBuiltinsResult is an internal SDK API and is not part of the +// public surface. +type AgentsGetAvailableBuiltinsResult struct { + // Available shipped agents, in the runtime's own order. + // Internal: Agents is part of the SDK's internal API surface and is not intended for + // external use. + Agents []BuiltinAgentSummary `json:"agents"` +} + +// The shipped agent whose definition to load. +// Experimental: AgentsGetBuiltinDefinitionRequest is part of an experimental API and may +// change or be removed. +// Internal: AgentsGetBuiltinDefinitionRequest is an internal SDK API and is not part of the +// public surface. +type AgentsGetBuiltinDefinitionRequest struct { + // The agent name, which must be one of `getBuiltins`'s `yamlBasedNames`. A name outside + // that list is special-cased in code and has no definition, and is reported as an error + // rather than as an empty definition. + Name string `json:"name"` +} + +// One shipped agent's definition. +// Experimental: AgentsGetBuiltinDefinitionResult is part of an experimental API and may +// change or be removed. +// Internal: AgentsGetBuiltinDefinitionResult is an internal SDK API and is not part of the +// public surface. +type AgentsGetBuiltinDefinitionResult struct { + // The agent's definition, serialized as JSON. It carries the authored keys plus the + // runtime's projected `__nativeCustomAgent` view of the same agent. It is a string rather + // than an object because the runtime parses it with the agent schema's tolerant shape, + // which accepts keys this contract does not name. + DefinitionJSON string `json:"definitionJson"` +} + +// The shipped agent whose listing entry to load. +// Experimental: AgentsGetBuiltinListingDefinitionRequest is part of an experimental API and +// may change or be removed. +// Internal: AgentsGetBuiltinListingDefinitionRequest is an internal SDK API and is not part +// of the public surface. +type AgentsGetBuiltinListingDefinitionRequest struct { + // The agent name, taken from `getAvailableBuiltins`. Unlike `getBuiltinDefinition`, the + // agent that `getBuiltins` reports as special-cased rather than YAML-based is answered here + // too, from its in-code definition. + Name string `json:"name"` +} + +// One shipped agent, projected for a listing. +// Experimental: AgentsGetBuiltinListingDefinitionResult is part of an experimental API and +// may change or be removed. +// Internal: AgentsGetBuiltinListingDefinitionResult is an internal SDK API and is not part +// of the public surface. +type AgentsGetBuiltinListingDefinitionResult struct { + // The agent projected as a custom agent, serialized as JSON. It is a string rather than an + // object for the same reason as `getBuiltinDefinition`: the runtime parses the underlying + // definition with the agent schema's tolerant shape, which accepts keys this contract does + // not name. + DefinitionJSON string `json:"definitionJson"` +} + +// The agents this runtime ships, named so a consumer can tell them apart from authored ones. +// Experimental: AgentsGetBuiltinsResult is part of an experimental API and may change or be +// removed. +// Internal: AgentsGetBuiltinsResult is an internal SDK API and is not part of the public +// surface. +type AgentsGetBuiltinsResult struct { + // The subset of `names` a user is allowed to turn off. A shipped agent outside this list is + // always active and a client should not offer a toggle for it. + DisableableNames []string `json:"disableableNames"` + // Every agent name this runtime ships. + Names []string `json:"names"` + // The subset of `names` defined by a shipped YAML definition. The remainder are + // special-cased in code and have no definition to load. + YamlBasedNames []string `json:"yamlBasedNames"` +} + // Optional project paths to include when enumerating agent discovery directories. // Experimental: AgentsGetDiscoveryPathsRequest is part of an experimental API and may // change or be removed. type AgentsGetDiscoveryPathsRequest struct { + // Explicit discovery-only agent roots to enumerate, including configured missing + // directories. Relative paths resolve against the request's effective working directory + // when supplied. These are not filesystem grants or preferred creation targets. Null and + // omission are equivalent. + AgentDirectories []string `json:"agentDirectories,omitzero"` // When true, omit the host's user-level agent directory, leaving only project directories. // For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). ExcludeHostAgents *bool `json:"excludeHostAgents,omitempty"` @@ -1034,6 +1255,21 @@ func (r RawAuthInfoData) Type() AuthInfoType { return r.Discriminator } +// An interactive account whose model provider owns its credentials. It carries no GitHub +// credential. +// Experimental: AccountAuthInfo is part of an experimental API and may change or be removed. +type AccountAuthInfo struct { + // Host coordinate owned by the account's model provider. + Host string `json:"host"` + // Login identifying the provider-owned account. + Login string `json:"login"` +} + +func (AccountAuthInfo) authInfo() {} +func (AccountAuthInfo) Type() AuthInfoType { + return AuthInfoTypeAccount +} + // Authentication-info input variant for API-key authentication to a non-GitHub LLM // provider, carrying the secret `apiKey` and host. // Experimental: APIKeyAuthInfo is part of an experimental API and may change or be removed. @@ -1193,6 +1429,20 @@ func (UserAuthInfo) Type() AuthInfoType { return AuthInfoTypeUser } +// A credential-free account choice after sign-in. +// Experimental: AuthLoginAccount is part of an experimental API and may change or be +// removed. +type AuthLoginAccount struct { + // Host coordinate owned by the selected account's provider. + Host string `json:"host"` + // Provider kind that owns this account choice. + Kind AccountKind `json:"kind"` + // Human-readable login for the account choice. + Login string `json:"login"` + // Opaque identifier supplied to the next login step to select this account. + SelectionID string `json:"selectionId"` +} + // Advance an in-flight login flow, optionally fulfilling an input-required step. // Experimental: AuthLoginAdvanceRequest is part of an experimental API and may change or be // removed. @@ -1229,15 +1479,18 @@ type AuthLoginCancelRequest struct { FlowID string `json:"flowId"` } -// Terminal result of an interactive login flow. +// Result of an interactive login flow. Pending consent or account selection is not terminal. // Experimental: AuthLoginResultDto is part of an experimental API and may change or be // removed. type AuthLoginResultDto struct { + // Available accounts when sign-in is awaiting account selection, ordered with Microsoft 365 + // first. + Accounts []AuthLoginAccount `json:"accounts,omitzero"` // Host that was signed in, when completed. Host *string `json:"host,omitempty"` // Login that was signed in, when completed. Login *string `json:"login,omitempty"` - // Terminal disposition of the login. + // Current disposition of the login, including pending user decisions. Status AuthLoginResultStatus `json:"status"` } @@ -1271,7 +1524,8 @@ func (AuthLoginStepAwaiting) Kind() AuthLoginStepKind { } type AuthLoginStepCompleted struct { - // The terminal login result. + // Login result. When status is needs-plaintext-consent or needs-account-selection, advance + // with the user's decision to continue. Result AuthLoginResultDto `json:"result"` } @@ -1380,6 +1634,9 @@ func (r RawAuthReadValueData) Kind() AuthReadValueKind { type AuthReadValueActiveAccount struct { // The active account, or absent when not logged in. Account *AccountStatus `json:"account,omitempty"` + // Credential-free identity metadata for the active account, including resolved Copilot user + // information when available. + AuthInfo *AuthIdentity `json:"authInfo,omitempty"` } func (AuthReadValueActiveAccount) authReadValue() {} @@ -1540,6 +1797,57 @@ type AutopilotObjectiveState struct { TurnCount int64 `json:"turnCount"` } +// A server-advertised routing preference. Identifiers and execution types are extensible. +// Experimental: AutoTierDescriptor is part of an experimental API and may change or be +// removed. +type AutoTierDescriptor struct { + // Description displayed beside the preference. + Description string `json:"description"` + // Human-readable label, not a routing identifier. + DisplayName string `json:"displayName"` + // Opaque routing identifier transmitted unchanged to the provider. + ID string `json:"id"` + // Current account-specific availability. + Status AutoTierStatus `json:"status"` + // Execution kind; this client supports `auto` preferences on the Auto model. + Type string `json:"type"` +} + +// Account-bound discovery metadata for the virtual `auto` model. +// Experimental: AutoTierMetadata is part of an experimental API and may change or be +// removed. +type AutoTierMetadata struct { + // Provider-default preference, used only when no explicit preference exists. + DefaultTier string `json:"defaultTier"` + // Provider that supplied this metadata, when the catalog is provider-attributed. + ProviderID *string `json:"providerId,omitempty"` + // Routing preferences in the server's presentation order. + Tiers []AutoTierDescriptor `json:"tiers"` +} + +// Availability of a server-advertised routing preference. +// Experimental: AutoTierStatus is part of an experimental API and may change or be removed. +type AutoTierStatus struct { + // Whether the provider permits selecting this preference. + Enabled bool `json:"enabled"` + // Human-readable explanation of availability. + Message *string `json:"message,omitempty"` + // Extensible machine-readable unavailability reason. + Reason *string `json:"reason,omitempty"` +} + +// A shipped agent, named and described. +// Experimental: BuiltinAgentSummary is part of an experimental API and may change or be +// removed. +// Internal: BuiltinAgentSummary is an internal SDK API and is not part of the public +// surface. +type BuiltinAgentSummary struct { + // One-line description of what the agent does. + Description string `json:"description"` + // The agent name, as it appears in `getBuiltins`. + Name string `json:"name"` +} + // The running runtime's complete catalog of well-known built-in model IDs, including // supported models and additional IDs with built-in metadata. // Experimental: BuiltInModelCatalog is part of an experimental API and may change or be @@ -3237,6 +3545,94 @@ type ConnectorDisconnectResult struct { Status ConnectorStatus `json:"status"` } +// Eligible account. +// Experimental: ConnectorDiscoveryAccount is part of an experimental API and may change or +// be removed. +type ConnectorDiscoveryAccount struct { + // Opaque account ID. + AccountID string `json:"accountId"` + // Account metadata. + AuthInfo ConnectorDiscoveryAuthInfo `json:"authInfo"` +} + +// Eligible accounts. +// Experimental: ConnectorDiscoveryAccountList is part of an experimental API and may change +// or be removed. +type ConnectorDiscoveryAccountList struct { + // Eligible accounts. + Accounts []ConnectorDiscoveryAccount `json:"accounts"` + // Availability. + Availability ConnectorDiscoveryAvailability `json:"availability"` +} + +// Selected account. +// Experimental: ConnectorDiscoveryAccountRequest is part of an experimental API and may +// change or be removed. +type ConnectorDiscoveryAccountRequest struct { + // Opaque account ID. + AccountID string `json:"accountId"` +} + +// Account metadata. +// Experimental: ConnectorDiscoveryAuthInfo is part of an experimental API and may change or +// be removed. +type ConnectorDiscoveryAuthInfo struct { + // Host. + Host string `json:"host"` + // Login. + Login string `json:"login"` + // Authentication type. + Type AuthInfoType `json:"type"` +} + +// Feature availability. +// Experimental: ConnectorDiscoveryCapabilities is part of an experimental API and may +// change or be removed. +type ConnectorDiscoveryCapabilities struct { + // API version. + APIVersion int64 `json:"apiVersion"` + // Availability. + Availability ConnectorDiscoveryAvailability `json:"availability"` + // Whether results are cached. + ConditionalCache bool `json:"conditionalCache"` + // Whether accounts are selected by opaque ID. + OpaqueAccountSelection bool `json:"opaqueAccountSelection"` +} + +// Entry. +// Experimental: ConnectorDiscoveryCatalogEntry is part of an experimental API and may +// change or be removed. +type ConnectorDiscoveryCatalogEntry struct { + // Description. + Description *string `json:"description,omitempty"` + // Display name. + DisplayName string `json:"displayName"` + // Logo. + Logo *string `json:"logo,omitempty"` + // Name. + Name string `json:"name"` + // Release tag. + ReleaseTag *string `json:"releaseTag,omitempty"` + // Status. + Status ConnectorCatalogStatus `json:"status"` + // Tier. + Tier *string `json:"tier,omitempty"` +} + +// Entries for the selected account. +// Experimental: ConnectorDiscoveryCatalogResult is part of an experimental API and may +// change or be removed. +type ConnectorDiscoveryCatalogResult struct { + // Opaque account ID. + AccountID string `json:"accountId"` + // Entries. + Connectors []ConnectorDiscoveryCatalogEntry `json:"connectors"` + // Refresh time in Unix epoch milliseconds. + RefreshedAtMs int64 `json:"refreshedAtMs"` + // Revision. + Revision int64 `json:"revision"` +} + // Requests authoritative Connector-to-MCP reconciliation for the pinned account. // Experimental: ConnectorReconcileRequest is part of an experimental API and may change or // be removed. @@ -3634,6 +4030,11 @@ type CurrentModel struct { // no plan override has captured a base model. Persistent agent model requirements apply to // this model rather than the temporary plan model. PlanBaseModelID *string `json:"planBaseModelId,omitempty"` + // Provider of planBaseModelId, when that saved selection is provider-qualified. + PlanBaseProviderID *string `json:"planBaseProviderId,omitempty"` + // Provider selected for this model. Together with modelId, identifies a catalog entry even + // when providers serve the same model. Omitted for unattributed legacy selections. + ProviderID *string `json:"providerId,omitempty"` // Reasoning effort level currently applied to the active model, when one is set. Reads // `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the // two values are reported as a snapshot. @@ -4645,6 +5046,126 @@ type ExternalToolTextResultForLlmContentResourceLinkIcon struct { Theme *ExternalToolTextResultForLlmContentResourceLinkIconTheme `json:"theme,omitempty"` } +// The declared shape of one feature flag, independent of any caller population. +// Experimental: FeatureFlagMetadata is part of an experimental API and may change or be +// removed. +// Internal: FeatureFlagMetadata is an internal SDK API and is not part of the public +// surface. +type FeatureFlagMetadata struct { + // The population the flag is declared for before any environment or user-settings override + // is applied. + // Internal: Availability is part of the SDK's internal API surface and is not intended for + // external use. + Availability FeatureFlagAvailability `json:"availability"` + // Whether the flag participates in the CAPI sanity suite. + CapiSanity bool `json:"capiSanity"` + // Text shown to a user choosing whether to turn the flag on in experimental mode. Absent + // when the flag is not user-facing. + ExperimentalDescription *string `json:"experimentalDescription,omitempty"` + // The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment + // rather than declared statically. + ExpFlag *string `json:"expFlag,omitempty"` + // Environment variable that overrides this flag's experiment assignment locally in the + // experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and + // derived from it, so a caller reads a local override without reproducing the naming rule. + ExpFlagEnvVar *string `json:"expFlagEnvVar,omitempty"` + // The flag's name, matching the key it is listed under. + Name string `json:"name"` +} + +// Every feature flag this runtime declares, with the shape each one was declared with. +// Experimental: FeatureFlagsMetadataResult is part of an experimental API and may change or +// be removed. +// Internal: FeatureFlagsMetadataResult is an internal SDK API and is not part of the public +// surface. +type FeatureFlagsMetadataResult struct { + // Declared feature flags keyed by flag name. + // Internal: Flags is part of the SDK's internal API surface and is not intended for + // external use. + Flags map[string]FeatureFlagMetadata `json:"flags"` +} + +// Caller population and overrides for static feature-flag resolution, independent of +// experiment assignments and active runtime state. +// Experimental: FeatureFlagsResolveRequest is part of an experimental API and may change or +// be removed. +// Internal: FeatureFlagsResolveRequest is an internal SDK API and is not part of the public +// surface. +type FeatureFlagsResolveRequest struct { + // Resolve against this already-computed flag set rather than each flag's declared + // availability. Keyed by flag name. + BaseFlags map[string]bool `json:"baseFlags,omitzero"` + // User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, + // and supported convenience settings. + Config any `json:"config,omitempty"` + // Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. + // Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's + // own environment. + Environment map[string]string `json:"environment,omitzero"` + // Flags forced to a value after every other layer, keyed by flag name. + FlagOverrides map[string]bool `json:"flagOverrides,omitzero"` + // Whether the caller is in an experimental population. + IsExperimental bool `json:"isExperimental"` + // Whether the caller is GitHub or Microsoft staff. + IsStaff bool `json:"isStaff"` + // GitHub-staff membership. Omit when it was never recorded: a legacy staff account then + // counts as both staff populations and keeps every staff feature. + IsStaffGitHub *bool `json:"isStaffGithub,omitempty"` + // Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + IsStaffMicrosoft *bool `json:"isStaffMicrosoft,omitempty"` + // Whether the caller belongs to the team population used by feature availability. + IsTeam bool `json:"isTeam"` +} + +// The resolved feature flags, keyed by flag name. +// Experimental: FeatureFlagsResolveResult is part of an experimental API and may change or +// be removed. +type FeatureFlagsResolveResult map[string]bool + +// Caller population and startup inputs to resolve named online-experiment gates for. +// Carries no account: the runtime resolves the assignment for the authentication it already +// holds. +// Experimental: FeatureFlagsResolveStartupGatesRequest is part of an experimental API and +// may change or be removed. +// Internal: FeatureFlagsResolveStartupGatesRequest is an internal SDK API and is not part +// of the public surface. +type FeatureFlagsResolveStartupGatesRequest struct { + // User settings document whose `featureFlags` block is layered on top of the resolved set. + Config any `json:"config,omitempty"` + // Environment to read flag overrides from. Defaults to this runtime process's own + // environment. + Environment map[string]string `json:"environment,omitzero"` + // When this installation first launched, in milliseconds since the Unix epoch. Experiments + // that segment on installation age read it. Omit when the first launch was never recorded. + FirstLaunchAtMillis *float64 `json:"firstLaunchAtMillis,omitempty"` + // The feature flags to resolve. A name this runtime does not declare is reported as an + // error rather than as a disabled flag. + Flags []string `json:"flags"` + // Whether the caller is in an experimental population. + IsExperimental bool `json:"isExperimental"` + // Whether the caller is GitHub or Microsoft staff. + IsStaff bool `json:"isStaff"` + // GitHub-staff membership. Omit when it was never recorded: a legacy staff account then + // counts as both staff populations and keeps every staff feature. + IsStaffGitHub *bool `json:"isStaffGithub,omitempty"` + // Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + IsStaffMicrosoft *bool `json:"isStaffMicrosoft,omitempty"` + // Whether the caller belongs to a team plan. + IsTeam bool `json:"isTeam"` + // Whether the runtime may refresh the cached assignment over the network without an active + // session. The refresh never blocks this call: the answer comes from the cache either way, + // so a refresh only affects a later launch. + RefreshWithoutSession bool `json:"refreshWithoutSession"` + // Whether streamer mode is on, which withholds the populations an experiment would + // otherwise segment on. + StreamerMode bool `json:"streamerMode"` +} + +// The resolved gates, keyed by flag name. +// Experimental: FeatureFlagsResolveStartupGatesResult is part of an experimental API and +// may change or be removed. +type FeatureFlagsResolveStartupGatesResult map[string]bool + // Content filtering mode to apply to all tools, or a map of tool name to content filtering // mode. // Experimental: FilterMapping is part of an experimental API and may change or be removed. @@ -4710,6 +5231,79 @@ type FolderTrustCheckResult struct { Trusted bool `json:"trusted"` } +// A folder to check against a persisted trusted-folders list, and the configuration +// directory holding that list. +// Experimental: FolderTrustIsTrustedParams is part of an experimental API and may change or +// be removed. +// Internal: FolderTrustIsTrustedParams is an internal SDK API and is not part of the public +// surface. +type FolderTrustIsTrustedParams struct { + // Configuration directory to read the trusted-folders list from. Omit it to read the + // default location; supply it when the host has redirected its configuration, or the check + // answers from a list the host is not using. + ConfigDir *string `json:"configDir,omitempty"` + // Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is + // listed, or when its git root is listed. + Path string `json:"path"` +} + +// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed +// device may pin Copilot to an approved set of GitHub organizations so a developer cannot +// sign in with a personal — or another enterprise's — account and escape every control that +// keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; +// the remaining fields explain the refusal rather than qualifying it. +// Experimental: ForceLoginOrgsDecision is part of an experimental API and may change or be +// removed. +// Internal: ForceLoginOrgsDecision is an internal SDK API and is not part of the public +// surface. +type ForceLoginOrgsDecision struct { + // Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is + // never blocked. + Allowed bool `json:"allowed"` + // A stable kebab-case reason code when refused: `org-not-approved`, + // `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or + // `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal + // rather than mapping it to an allow: a code this host has not been taught about still + // denied the credential. + Denial *string `json:"denial,omitempty"` + // Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed + // because the account is approved", which a diagnostics surface needs and which also + // decides whether a bring-your-own-key provider may serve inference. + Enforced bool `json:"enforced"` + // The approved organization the account matched, when allowed under a pin. + MatchedOrg *string `json:"matchedOrg,omitempty"` + // A developer-facing explanation of the refusal. Omitted when allowed. + Message *string `json:"message,omitempty"` + // Error-level detail from managed-policy discovery — which file failed to load, which field + // failed validation. Carried on the decision rather than left to the log because a refusal + // can exit the process before a log sink exists, which would discard the only actionable + // diagnostic a misconfigured managed device produces. + PolicyDiagnostics []string `json:"policyDiagnostics"` + // The approved organization logins, as configured. Enterprise configuration rather than + // user data, so it is safe to name in a message or a log line. + RequiredOrgs []string `json:"requiredOrgs"` +} + +// The remote the checked-out branch tracks. +// Experimental: GitCurrentBranchRemoteResult is part of an experimental API and may change +// or be removed. +// Internal: GitCurrentBranchRemoteResult is an internal SDK API and is not part of the +// public surface. +type GitCurrentBranchRemoteResult struct { + // Name of the tracked remote. Reports `origin` whenever the working tree has no tracking + // configuration to read, including on a detached HEAD, so this is never null and never + // empty. + Remote string `json:"remote"` +} + +// Working-tree path a git query applies to. +// Experimental: GitCwdRequest is part of an experimental API and may change or be removed. +// Internal: GitCwdRequest is an internal SDK API and is not part of the public surface. +type GitCwdRequest struct { + // Absolute path to a directory inside the git working tree to query. + Cwd string `json:"cwd"` +} + // Safe discovery information. Host-side relay bootstrap credentials are never included. // Experimental: GitHubEnvironment is part of an experimental API and may change or be // removed. @@ -4736,6 +5330,93 @@ type GitHubEnvironment struct { Status string `json:"status"` } +// A GitHub login the authenticated user may act as: their own account, or an organization +// they belong to. +// Experimental: GitHubOwnerOption is part of an experimental API and may change or be +// removed. +// Internal: GitHubOwnerOption is an internal SDK API and is not part of the public surface. +type GitHubOwnerOption struct { + // The owner's GitHub login. + Login string `json:"login"` + // Which kind of owner this is. The authenticated user's own account is always reported as + // `user`. + Type string `json:"type"` +} + +// The owner listing to abandon. +// Experimental: GitHubOwnersCancelRequest is part of an experimental API and may change or +// be removed. +// Internal: GitHubOwnersCancelRequest is an internal SDK API and is not part of the public +// surface. +type GitHubOwnersCancelRequest struct { + // Request id the listing was started with. + RequestID int64 `json:"requestId"` +} + +// Whether the id named a running owner listing. +// Experimental: GitHubOwnersCancelResult is part of an experimental API and may change or +// be removed. +// Internal: GitHubOwnersCancelResult is an internal SDK API and is not part of the public +// surface. +type GitHubOwnersCancelResult struct { + // True when a listing with the id was running and the cancel stopped it. False when the id + // was never registered, was registered but unused, was released after being abandoned, or + // its listing had ended. An unused id is released and cannot start a later listing. + Canceled bool `json:"canceled"` +} + +// Credential to list owners under, and the request id that makes the listing cancellable. +// Experimental: GitHubOwnersListRequest is part of an experimental API and may change or be +// removed. +// Internal: GitHubOwnersListRequest is an internal SDK API and is not part of the public +// surface. +type GitHubOwnersListRequest struct { + // The credential the listing runs under, carried opaquely because its shape is the host's + // own and the runtime only resolves a token and a GitHub host from it. No credential + // travels: this selects one the runtime already holds. + AuthInfo any `json:"authInfo"` + // Request id from `gitHubOwners.nextRequestId`. An id that was never registered, canceled + // before use, released after being abandoned, or already used is refused rather than + // silently running uncancellable. + RequestID int64 `json:"requestId"` +} + +// Outcome of an owner listing. Exactly one of `owners` and `message` is present, except +// that `throwError` reports a failure the caller is expected to raise rather than render. +// Experimental: GitHubOwnersListResult is part of an experimental API and may change or be +// removed. +// Internal: GitHubOwnersListResult is an internal SDK API and is not part of the public +// surface. +type GitHubOwnersListResult struct { + // Why no owners could be listed, phrased for a user. Present when the listing failed in a + // way the caller should render rather than raise. + Message *string `json:"message,omitempty"` + // The owners, on success: the authenticated user first, then the organizations they belong + // to. + // Internal: Owners is part of the SDK's internal API surface and is not intended for + // external use. + Owners []GitHubOwnerOption `json:"owners,omitzero"` + // A malformed request or an unreadable credential, which the caller raises instead of + // rendering. Kept a field rather than a dispatch error so it stays distinct from `message`, + // which the caller renders. + ThrowError *string `json:"throwError,omitempty"` + // A line the caller should log. Present only alongside `message`, and only for failures + // worth recording. + Warning *string `json:"warning,omitempty"` +} + +// A freshly registered request id. Registering it before the listing starts is what lets a +// cancel that races the request still find the owner listing slot. The id serves one +// listing only. Long-abandoned unused ids can be released by later allocations. +// Experimental: GitHubOwnersRequestIDResult is part of an experimental API and may change +// or be removed. +// Internal: GitHubOwnersRequestIDResult is an internal SDK API and is not part of the +// public surface. +type GitHubOwnersRequestIDResult struct { + // Request id to pass to `gitHubOwners.list` and, to abandon it, `gitHubOwners.cancel`. + RequestID int64 `json:"requestId"` +} + // Pointer to a GitHub repository. // Experimental: GitHubRepoRef is part of an experimental API and may change or be removed. type GitHubRepoRef struct { @@ -4747,6 +5428,39 @@ type GitHubRepoRef struct { Owner string `json:"owner"` } +// Working-tree path whose owning GitHub repository should be resolved. +// Experimental: GitHubRepositoryAtPathRequest is part of an experimental API and may change +// or be removed. +// Internal: GitHubRepositoryAtPathRequest is an internal SDK API and is not part of the +// public surface. +type GitHubRepositoryAtPathRequest struct { + // Absolute path to a directory inside the git working tree to resolve. + Path string `json:"path"` +} + +// The GitHub repository that owns the requested path, when the selected remote (`origin`, +// else the first) is on a GitHub host. +// Experimental: GitHubRepositoryAtPathResult is part of an experimental API and may change +// or be removed. +// Internal: GitHubRepositoryAtPathResult is an internal SDK API and is not part of the +// public surface. +type GitHubRepositoryAtPathResult struct { + // Resolved repository identity, or null when the selected remote resolves to no GitHub host. + Repository *GitHubRepositoryIdentity `json:"repository,omitempty"` +} + +// Owner, name, and host of a GitHub repository, as resolved from a git remote URL. +// Experimental: GitHubRepositoryIdentity is part of an experimental API and may change or +// be removed. +type GitHubRepositoryIdentity struct { + // Host the remote points at, for example `github.com` or a GitHub Enterprise hostname. + Host string `json:"host"` + // Repository name, without the owner prefix or the `.git` suffix. + Name string `json:"name"` + // Repository owner login (user or organization). + Owner string `json:"owner"` +} + // Client environment metadata describing the process that produced a telemetry event. // Experimental: GitHubTelemetryClientInfo is part of an experimental API and may change or // be removed. @@ -4883,6 +5597,140 @@ func (GitHubTokenAcquireResultToken) Kind() GitHubTokenAcquireResultKind { return GitHubTokenAcquireResultKindToken } +// A GitHub repository one of a working tree's remotes points at. +// Experimental: GitRemoteRepository is part of an experimental API and may change or be +// removed. +// Internal: GitRemoteRepository is an internal SDK API and is not part of the public +// surface. +type GitRemoteRepository struct { + // GitHub host serving the repository, which is not `github.com` for a GitHub Enterprise + // remote. + Host string `json:"host"` + // Repository name, without the owner. + Name string `json:"name"` + // Account or organization owning the repository. + Owner string `json:"owner"` + // Name of the first remote that produced this distinct repository entry, such as `origin` + // or `upstream`. + RemoteName string `json:"remoteName"` +} + +// Git working tree whose GitHub remotes should be listed. +// Experimental: GitReposFromRemotesRequest is part of an experimental API and may change or +// be removed. +// Internal: GitReposFromRemotesRequest is an internal SDK API and is not part of the public +// surface. +type GitReposFromRemotesRequest struct { + // Absolute path to the root of the git working tree. + GitRoot string `json:"gitRoot"` +} + +// The GitHub repositories a working tree's remotes point at. +// Experimental: GitReposFromRemotesResult is part of an experimental API and may change or +// be removed. +// Internal: GitReposFromRemotesResult is an internal SDK API and is not part of the public +// surface. +type GitReposFromRemotesResult struct { + // One entry per distinct GitHub repository, in the order git reports the first remote for + // each repository. Empty when no remote points at a GitHub host, which a caller should read + // as `not connected to GitHub`. Failing to read the remotes is an error, not an empty list. + // Internal: Repositories is part of the SDK's internal API surface and is not intended for + // external use. + Repositories []GitRemoteRepository `json:"repositories"` +} + +// Selects the configuration directory whose machine-wide state to read. +// Experimental: GlobalStateLoadForConfigDirRequest is part of an experimental API and may +// change or be removed. +// Internal: GlobalStateLoadForConfigDirRequest is an internal SDK API and is not part of +// the public surface. +type GlobalStateLoadForConfigDirRequest struct { + // Copilot configuration directory to read the state document from, taking precedence over + // the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to + // read the directory the server resolved for itself. + ConfigDir *string `json:"configDir,omitempty"` +} + +// The host's machine-wide state. Every field is optional because a fresh install has +// recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a +// negative answer. Stored credentials are deliberately absent from this shape. +// Experimental: GlobalStateLoadResult is part of an experimental API and may change or be +// removed. +// Internal: GlobalStateLoadResult is an internal SDK API and is not part of the public +// surface. +type GlobalStateLoadResult struct { + // Whether the app tip has been shown. + AppTipShown *bool `json:"appTipShown,omitempty"` + // Terminals the user has already been asked to set up, so the host does not ask twice. + AskedSetupTerminals []string `json:"askedSetupTerminals,omitzero"` + // When the Auto-feedback hint was last shown, as an ISO 8601 timestamp. It enforces the + // once-per-day cap for non-staff users across restarts. + AutoFeedbackLastPromptedAt *string `json:"autoFeedbackLastPromptedAt,omitempty"` + // When the host first ran on this machine. + FirstLaunchAt *string `json:"firstLaunchAt,omitempty"` + // Plugins installed on this machine. + InstalledPlugins []InstalledPlugin `json:"installedPlugins,omitzero"` + // Account used for the most recent sign-in. + // Internal: LastLoggedInUser is part of the SDK's internal API surface and is not intended + // for external use. + LastLoggedInUser *LoggedInUser `json:"lastLoggedInUser,omitempty"` + // Every account the host has signed in to on this machine. + // Internal: LoggedInUsers is part of the SDK's internal API surface and is not intended for + // external use. + LoggedInUsers []LoggedInUser `json:"loggedInUsers,omitzero"` + // Whether the one-off cleanup of stored reasoning summaries has run. + ReasoningSummariesCleanupDone *bool `json:"reasoningSummariesCleanupDone,omitempty"` + // Models the user selected recently, most recent first. + RecentModelIDs []string `json:"recentModelIds,omitzero"` + // Whether the user declined to trust the sandbox credential proxy CA. + SandboxCredentialProxyCaDeclined *bool `json:"sandboxCredentialProxyCaDeclined,omitempty"` + // Whether the sandbox onboarding has been shown. + SandboxOnboardingShown *bool `json:"sandboxOnboardingShown,omitempty"` + // Whether the user is a GitHub or Microsoft staff member, which unlocks internal-only + // behavior. + Staff *bool `json:"staff,omitempty"` + // Whether the user was recognized as GitHub staff. + StaffGitHub *bool `json:"staffGithub,omitempty"` + // When the staff-only log level migration last ran. + StaffLogLevelMigrationAt *string `json:"staffLogLevelMigrationAt,omitempty"` + // Whether the user was recognized as Microsoft staff. + StaffMicrosoft *bool `json:"staffMicrosoft,omitempty"` + // When the staff-only model reset last ran. + StaffModelResetAt *string `json:"staffModelResetAt,omitempty"` + // When the staff-only update channel migration last ran. + StaffUpdateChannelMigrationAt *string `json:"staffUpdateChannelMigrationAt,omitempty"` + // Folders where the user declined the init prompt, so it stays hidden there. + SuppressInitFolders []string `json:"suppressInitFolders,omitzero"` + // Folders the user has marked as trusted. + TrustedFolders []string `json:"trustedFolders,omitzero"` +} + +// A single top-level key to record in the host's machine-wide state. The write replaces +// only that key and leaves the rest of the document untouched, so two writers recording +// different one-off flags do not overwrite each other. The stored credential keys cannot be +// written through this method. +// Experimental: GlobalStateWriteKeyRequest is part of an experimental API and may change or +// be removed. +// Internal: GlobalStateWriteKeyRequest is an internal SDK API and is not part of the public +// surface. +type GlobalStateWriteKeyRequest struct { + // Copilot configuration directory to write the state document in, taking precedence over + // the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to + // write the directory the server resolved for itself. Mirrors + // `globalState.loadForConfigDir`, so a caller can read and write the same directory. + ConfigDir *string `json:"configDir,omitempty"` + // Top-level key to write, named as it appears in the result of `globalState.load`. It must + // be one of the writable keys that `globalState.writeKey` lists. + Key string `json:"key"` + // Value to store for the key. Omit it, or pass null, to remove the key instead. + Value any `json:"value,omitempty"` +} + +// Experimental: GlobalStateWriteKeyResult is part of an experimental API and may change or +// be removed. +type GlobalStateWriteKeyResult struct { +} + // Pending external tool call request ID, with the tool result or an error describing why it // failed. // Experimental: HandlePendingToolCallRequest is part of an experimental API and may change @@ -5189,6 +6037,12 @@ type HooksDiscoverRequest struct { // still contribute to each remaining row's effective enabled state. This filters sources // rather than simulating a host with no settings. ExcludeHostHooks *bool `json:"excludeHostHooks,omitempty"` + // Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + // grants. Available without ambient discovery or repository file-hook enablement, subject + // to managed/hook disables. Relative paths resolve against the request's effective working + // directory when supplied. Null and omission are equivalent; an empty array contributes no + // explicit roots. + HookDirectories []string `json:"hookDirectories,omitzero"` // Optional project directory paths whose trusted repository and project-expanded plugin // hooks should be discovered. When omitted or empty, user, managed-policy, and globally // enabled installed or explicit plugin hooks are returned without project expansion. @@ -5325,6 +6179,28 @@ type HostGitHubEnvironmentOptions struct { ComputeID string `json:"computeId"` // Human-readable environment display name. Name string `json:"name"` + // Require sealed, connection-bound authentication (default true), independent of listener + // address. False permits unsealed direct credentials and unbound sealed relay credentials; + // use only when the caller fully controls and trusts the direct transport. Relay token + // encryption remains mandatory. + RequireConnectionBinding *bool `json:"requireConnectionBinding,omitempty"` +} + +// Reads a running host's catalog or the runtime's saved default catalog. +// Experimental: HostListSessionsRequest is part of an experimental API and may change or be +// removed. +type HostListSessionsRequest struct { + // Listener UUID returned by host.start; the caller must own it. Omit to read + // the saved default compute-identity catalog without starting a listener. + HostID *string `json:"hostId,omitempty"` +} + +// The complete live and dormant advertised catalog, without subscribing to sessions. +// Experimental: HostListSessionsResult is part of an experimental API and may change or be +// removed. +type HostListSessionsResult struct { + // Complete advertised session summaries, in the host's catalog order. + Sessions []HostSessionSummary `json:"sessions"` } // Normalized local WebSocket listener settings. @@ -5419,6 +6295,8 @@ type HostRegisterSessionRequest struct { } // The existing runtime identity and its resource on the listener. +// Experimental: HostRegisterSessionResult is part of an experimental API and may change or +// be removed. type HostRegisterSessionResult struct { // Canonical runtime ID of the published session. SessionID string `json:"sessionId"` @@ -5454,6 +6332,9 @@ type HostSessionCreateRequest struct { Config map[string]any `json:"config"` // Unique identity for this participation, independent of the session lifetime. HandoffID string `json:"handoffId"` + // For an explicit publication, borrow an existing owning-connection resident + // instead of invoking the resume factory. Cold sessions still use the factory. + PreferResident *bool `json:"preferResident,omitempty"` // Resume an app-owned durable session instead of creating a new session. Resume *bool `json:"resume,omitempty"` } @@ -5489,6 +6370,25 @@ type HostSessionReleaseRequest struct { HandoffID string `json:"handoffId"` } +// Metadata advertised by the AHP host, not a guarantee that history can be resumed. +// Experimental: HostSessionSummary is part of an experimental API and may change or be +// removed. +type HostSessionSummary struct { + // Optional activity description advertised by the host. + Activity *string `json:"activity,omitempty"` + // Session creation time as an ISO 8601 timestamp. + CreatedAt string `json:"createdAt"` + // Last modification time as an ISO 8601 timestamp. + ModifiedAt string `json:"modifiedAt"` + // Stable AHP resource URI identifying the session on this host. + Resource string `json:"resource"` + // Unsigned 32-bit AHP session status bitset (0..=4294967295); unknown bits must be + // preserved. + Status int64 `json:"status"` + // Authoritative title advertised by the host. + Title string `json:"title"` +} + // Empty acknowledgement for a completed host lifecycle operation. // Experimental: HostShutdownResult is part of an experimental API and may change or be // removed. @@ -5499,6 +6399,9 @@ type HostShutdownResult struct { // Experimental: HostStartRequest is part of an experimental API and may change or be // removed. type HostStartRequest struct { + // Stable application identity selecting its durable host catalog. Defaults to the persisted + // runtime compute GUID; must agree with githubEnvironment.computeId when both are supplied. + ComputeID *string `json:"computeId,omitempty"` // Registers a GitHub Mission Control environment and enables its relay transport. GitHubEnvironment *HostGitHubEnvironmentOptions `json:"githubEnvironment,omitempty"` // Caller-generated UUID identifying this connection-owned listener. @@ -5783,6 +6686,37 @@ type InstructionDiscoveryPathList struct { Paths []InstructionDiscoveryPath `json:"paths"` } +// Experimental: InstructionsClearCacheResult is part of an experimental API and may change +// or be removed. +type InstructionsClearCacheResult struct { +} + +// Explicit discovery arguments for one location, supplied by the caller rather than derived +// from a session. +// Experimental: InstructionsDiscoverRepoSourcesRequest is part of an experimental API and +// may change or be removed. +// Internal: InstructionsDiscoverRepoSourcesRequest is an internal SDK API and is not part +// of the public surface. +type InstructionsDiscoverRepoSourcesRequest struct { + // Extra directories to scan alongside instruction directories configured in the runtime + // environment. + AdditionalDirs []string `json:"additionalDirs,omitzero"` + // Copilot configuration directory for user-level sources. An omitted or empty value uses + // the server's configuration home. + ConfigDir *string `json:"configDir,omitempty"` + // Working directory whose instruction sources should also be included. Omission adds no + // separate working-directory scope. + CwdPath *string `json:"cwdPath,omitempty"` + // When true, also discover instruction files nested below the location. + EnableChildInstructions *bool `json:"enableChildInstructions,omitempty"` + // When true, include the sources a command-line host reads. Hosts that are not the CLI omit + // it. + IsCLI *bool `json:"isCli,omitempty"` + // Repository location to discover. An empty string selects no repository scope; cwdPath can + // still supply working-directory sources. + Location string `json:"location"` +} + // Optional project paths to include in instruction discovery. // Experimental: InstructionsDiscoverRequest is part of an experimental API and may change // or be removed. @@ -5790,6 +6724,11 @@ type InstructionsDiscoverRequest struct { // When true, omit the host's instruction sources (user/home-level files and plugin rules), // leaving only repository and working-directory sources. For multitenant deployments. ExcludeHostInstructions *bool `json:"excludeHostInstructions,omitempty"` + // Explicit discovery-only instruction roots using existing SDK instruction formats, not + // filesystem grants. Available without ambient discovery, subject to instruction/managed + // disables. Relative paths resolve against the request's effective working directory when + // supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Optional list of project directory paths to scan for repository/working-directory // instruction sources. When omitted or empty, only user-level and plugin instruction // sources are returned (no project scan). @@ -5803,6 +6742,11 @@ type InstructionsGetDiscoveryPathsRequest struct { // When true, omit the host's user-level instruction targets, leaving only repository // targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). ExcludeHostInstructions *bool `json:"excludeHostInstructions,omitempty"` + // Explicit discovery-only instruction roots to enumerate, including configured missing + // directories. Relative paths resolve against the request's effective working directory + // when supplied. These are not filesystem grants or preferred creation targets. Null and + // omission are equivalent. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Optional list of project directory paths. When omitted or empty, only the user-level // targets are returned. ProjectPaths []string `json:"projectPaths,omitzero"` @@ -5816,6 +6760,16 @@ type InstructionsGetSourcesResult struct { Sources []InstructionSource `json:"sources"` } +// The prompt the init command runs. +// Experimental: InstructionsInitPromptResult is part of an experimental API and may change +// or be removed. +// Internal: InstructionsInitPromptResult is an internal SDK API and is not part of the +// public surface. +type InstructionsInitPromptResult struct { + // Prompt text authoring repository instructions. + Prompt string `json:"prompt"` +} + // Loaded instruction source for a session, including path, content, category, location, // applicability, and optional description. // Experimental: InstructionSource is part of an experimental API and may change or be @@ -6083,6 +7037,32 @@ type LocalSessionMetadataValue struct { Summary *string `json:"summary,omitempty"` } +// Which stored location permissions were dropped because their directory is gone. +// Experimental: LocationPermissionsCleanupResult is part of an experimental API and may +// change or be removed. +// Internal: LocationPermissionsCleanupResult is an internal SDK API and is not part of the +// public surface. +type LocationPermissionsCleanupResult struct { + // Location keys whose grants were removed. Empty when every stored location still exists. + RemovedLocationKeys []string `json:"removedLocationKeys"` +} + +// An account the host has signed in to, identified by the server it lives on and the login +// it uses there. The same person can appear more than once when they use both github.com +// and an Enterprise server. +// Experimental: LoggedInUser is part of an experimental API and may change or be removed. +// Internal: LoggedInUser is an internal SDK API and is not part of the public surface. +type LoggedInUser struct { + // Source account this account was derived from, when one was recorded. + DerivedFrom *string `json:"derivedFrom,omitempty"` + // Host the account belongs to, such as `github.com` or an Enterprise server. + Host string `json:"host"` + // Account kind, when the host recorded one. Consumers must tolerate new strings. + Kind *string `json:"kind,omitempty"` + // Account login on that host. + Login string `json:"login"` +} + // Message text, optional severity level, persistence flag, optional follow-up URL, and // optional tip. // Experimental: LogRequest is part of an experimental API and may change or be removed. @@ -6142,6 +7122,70 @@ type ManagedMCPServerConfig struct { URL string `json:"url"` } +// Experimental: ManagedPermissionEvaluation is part of an experimental API and may change +// or be removed. +type ManagedPermissionEvaluation struct { + // Original input operation associated with this verdict. + Operation ManagedPermissionOperation `json:"operation"` + // Managed-policy decision only; never bypasses user permissions or other security controls. + Verdict ManagedPermissionVerdict `json:"verdict"` +} + +// Experimental: ManagedPermissionOperation is part of an experimental API and may change or +// be removed. +type ManagedPermissionOperation struct { + // Operation to evaluate. Currently only url is supported. + Kind ManagedPermissionOperationKind `json:"kind"` + // Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. + URL string `json:"url"` +} + +// Reusable managed permission evaluation context. Treat permissions as runtime-owned policy +// data and retain it verbatim; it includes source-aware composition metadata. This is a +// snapshot, not a capability or approval token; only use contexts obtained from trusted +// policy sources. +// Experimental: ManagedPermissionsContext is part of an experimental API and may change or +// be removed. +type ManagedPermissionsContext struct { + // Policy could not be determined; evaluation must deny every operation. + FailClosed bool `json:"failClosed"` + // Runtime-owned composed permissions object. Absent when no permission policy is configured. + Permissions any `json:"permissions,omitempty"` +} + +// Managed policy context and ordered operations for pure, sessionless evaluation. +// Experimental: ManagedPermissionsEvaluateRequest is part of an experimental API and may +// change or be removed. +type ManagedPermissionsEvaluateRequest struct { + // Trusted, reusable managed permission policy snapshot; no policy is discovered during + // evaluation. + Context ManagedPermissionsContext `json:"context"` + // Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + Operations []ManagedPermissionOperation `json:"operations"` +} + +// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +// Experimental: ManagedPermissionsEvaluateResult is part of an experimental API and may +// change or be removed. +type ManagedPermissionsEvaluateResult struct { + // Managed permission policy could not be determined; every operation is denied. + FailClosed bool `json:"failClosed"` + // One verdict per input operation, in the same order, including duplicates. + Results []ManagedPermissionEvaluation `json:"results"` +} + +// Retry outcome for one plugin required by managed settings. +// Experimental: ManagedPluginRetryEntry is part of an experimental API and may change or be +// removed. +type ManagedPluginRetryEntry struct { + // Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. + Error *string `json:"error,omitempty"` + // Plugin spec in "plugin@marketplace" form. + Spec string `json:"spec"` + // What the retry did for this plugin. + Status ManagedPluginRetryStatus `json:"status"` +} + // Lock state and provenance of one managed setting. // Experimental: ManagedSettingMeta is part of an experimental API and may change or be // removed. @@ -6149,12 +7193,40 @@ type ManagedSettingMeta struct { // Whether users and repositories may choose a different value. `false` means policy locks // the value. Overridable bool `json:"overridable"` + // Original managed value when the runtime adjusted it to a supported effective value. + // Omitted when no adjustment was needed. + Requested *string `json:"requested,omitempty"` // Channel that supplied this scalar value, matching a `layers[].source`: `device`, // `server`, or `policyHelper`. These scalar defaults select one winning channel, not a // mixed source. Treat unknown values as additional channels; more may be added. Source string `json:"source"` } +// A user settings document and the effective managed policy whose controlled entries should +// be stamped onto it. +// Experimental: ManagedSettingsApplyControlsParams is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsApplyControlsParams is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsApplyControlsParams struct { + // The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. + // Omit it on an unmanaged host: the settings then come back unchanged. + Managed any `json:"managed,omitempty"` + // The user settings document to stamp. Entries the managed layer does not name are returned + // exactly as supplied. + Settings any `json:"settings"` +} + +// The user settings with the managed layer's controlled entries stamped on. +// Experimental: ManagedSettingsApplyControlsResult is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsApplyControlsResult is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsApplyControlsResult struct { + // The resulting settings document. + SettingsJSON any `json:"settingsJson"` +} + // Experimental: ManagedSettingsClearCacheResult is part of an experimental API and may // change or be removed. type ManagedSettingsClearCacheResult struct { @@ -6217,6 +7289,151 @@ type ManagedSettingsDiagnostic struct { Severity ManagedSettingsDiagnosticSeverity `json:"severity"` } +// Inputs describing the host and account an ingestion should resolve managed policy for. +// Experimental: ManagedSettingsIngestParams is part of an experimental API and may change +// or be removed. +// Internal: ManagedSettingsIngestParams is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsIngestParams struct { + // The authenticated identity to resolve policy for. Omitted before sign-in, in which case + // no server layer is fetched. + AuthInfo any `json:"authInfo,omitempty"` + // Whether to ignore a cached server policy when reading, forcing the resolution to come + // from a live fetch. + BypassCacheRead *bool `json:"bypassCacheRead,omitempty"` + // Name of the embedding client, reported to the managed-settings service as `client_id` so + // it can refuse to deliver a policy this client is too old to enforce. Omit it and the + // runtime reports a generic identity; the runtime version sent alongside is the gate that + // actually matters. + ClientName *string `json:"clientName,omitempty"` + // A device layer supplied by the host instead of discovered from the machine. Pair it with + // `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The host's environment variables, read for cache location and policy overrides. Supplied + // by the host rather than read from the runtime process so a command that selected its own + // configuration home is honored. + Environment any `json:"environment"` + // Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + // the device layer is empty; false discovers it from the machine. + HasDeviceResponse *bool `json:"hasDeviceResponse,omitempty"` + // The host's home directory, used to resolve cache and managed-file locations. + HomeDirectory string `json:"homeDirectory"` + // The host's platform, in Node's `process.platform` spelling, used to locate + // platform-specific cache and policy paths. + Platform string `json:"platform"` + // Whether a configured platform policy helper may be run to produce an enforced helper + // layer. + PolicyHelperEnabled *bool `json:"policyHelperEnabled,omitempty"` + // The policy-helper invocation reason. Defaults to sessionStart. + // Internal: PolicyHelperReason is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperReason *ManagedSettingsPolicyHelperReason `json:"policyHelperReason,omitempty"` + // Directory the policy helper runs in when this ingestion is not owned by a registered + // session. A host resolving policy before its session exists must pass this, or a + // directory-sensitive helper judges the wrong repository. + PolicyHelperWorkingDirectory *string `json:"policyHelperWorkingDirectory,omitempty"` + // Whether to run ingestion. Omit or set false to return an empty result without discovering + // or fetching policy. + SelfFetch *bool `json:"selfFetch,omitempty"` + // How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own + // policy when omitted. + // Internal: ServerPolicyCacheMode is part of the SDK's internal API surface and is not + // intended for external use. + ServerPolicyCacheMode *ManagedSettingsServerPolicyCacheMode `json:"serverPolicyCacheMode,omitempty"` + // The session whose credential store and working directory the policy helper should use. + // Omit it when no session exists yet and the process-wide store applies. + SessionID *string `json:"sessionId,omitempty"` + // User agent to send with the policy fetch. + UserAgent string `json:"userAgent"` +} + +// The managed policy layers an ingestion resolved, together with the per-layer outcome +// flags a host needs to decide how much to trust the result. The flags are reported rather +// than folded into the settings because a host must be able to distinguish an unmanaged +// device from a managed device whose policy could not be confirmed, and apply its +// fail-closed gates in the second case. +// Experimental: ManagedSettingsIngestResult is part of an experimental API and may change +// or be removed. +// Internal: ManagedSettingsIngestResult is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsIngestResult struct { + // The device layer could not be read, so it is unconfirmed rather than known-absent. + DeviceLoadFailed bool `json:"deviceLoadFailed"` + // The device layer discovered from the machine, when one exists. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The sandbox floor contributed by the device layer. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // Whether the device layer's sandbox intent could not be determined, so a consumer must not + // read its absence as permission to run unsandboxed. + DeviceSandboxUndetermined bool `json:"deviceSandboxUndetermined"` + // A device-managed policy is known to exist. + DeviceSourceFound bool `json:"deviceSourceFound"` + // Diagnostics emitted while resolving the layers, in the order they occurred. + // Internal: LogMessages is part of the SDK's internal API surface and is not intended for + // external use. + LogMessages []ManagedSettingsLogMessage `json:"logMessages"` + // The effective managed permissions layer, when the resolved policy carries one. + Permissions any `json:"permissions,omitempty"` + // Which channel registered the policy helper that produced the helper layer. + // Internal: PolicyHelperAuthority is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperAuthority *ManagedSettingsPolicyHelperAuthority `json:"policyHelperAuthority,omitempty"` + // A policy helper is configured for this host. + PolicyHelperConfigured bool `json:"policyHelperConfigured"` + // The policy helper's failure must be treated as fail-closed rather than ignored. + PolicyHelperFailClosed bool `json:"policyHelperFailClosed"` + // The policy helper was configured but could not be run or its output could not be read. + PolicyHelperLoadFailed bool `json:"policyHelperLoadFailed"` + // The layer produced by the platform policy helper, when one ran. + PolicyHelperResponse any `json:"policyHelperResponse,omitempty"` + // A live fetch failed but a recent cached entry was served in its place, so + // `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a + // cache-backed fallback. + ServerCacheFallback bool `json:"serverCacheFallback"` + // Minimum client version requested by a successful response. Advisory only; the delivered + // policy remains active. + ServerClientUpdateRequested *string `json:"serverClientUpdateRequested,omitempty"` + // The server refused to deliver a policy because this client is too old to enforce it, + // carrying the user-facing sentence describing the refusal. No retry will help; the remedy + // is a client update. Gates that exist only because of managed policy should deny on this + // rather than falling back to their unmanaged default. + ServerClientUpdateRequired *string `json:"serverClientUpdateRequired,omitempty"` + // The error that made the server fetch fail, when one did. + ServerFetchError *string `json:"serverFetchError,omitempty"` + // The server fetch failed and no cached entry stood in for it, so the server layer is + // unconfirmed and fail-closed gates apply. + ServerFetchFailed bool `json:"serverFetchFailed"` + // The server fetch failed while a policy demanded a fresh confirmation, which is the strict + // posture an enterprise opted into rather than an ordinary transient failure. + ServerForcedRefreshFailure bool `json:"serverForcedRefreshFailure"` + // The synthesized fail-closed permissions layer applied in place of a policy a refused + // client may not enforce. + ServerPermissionsFloor any `json:"serverPermissionsFloor,omitempty"` + // How the server layer was resolved. + // Internal: ServerResolution is part of the SDK's internal API surface and is not intended + // for external use. + ServerResolution ManagedSettingsServerPolicyResolution `json:"serverResolution"` + // The account's server-delivered policy, when one was resolved. + ServerResponse any `json:"serverResponse,omitempty"` + // The server fetch failed in a way a later retry could succeed at, as opposed to a refusal + // that no retry will change. + ServerRetryableFailure bool `json:"serverRetryableFailure"` + // The sandbox object from a cached server policy that a forced refresh declined to serve in + // full. Folded back into the effective sandbox layer so an outage during a forced refresh + // still synthesizes the fail-closed sandbox floor from the administrator's known intent. + ServerSandboxFloor any `json:"serverSandboxFloor,omitempty"` + // A server-managed policy is known to exist even though `serverResponse` is intentionally + // unset. Consumers should OR this with the presence of `serverResponse` when deciding + // whether the device is managed, so a fresh start during an outage still applies the + // fail-closed gates instead of treating the device as unmanaged. + ServerSourceFound bool `json:"serverSourceFound"` + // No usable token was available, so no server fetch was attempted. + ServerTokenUnavailable bool `json:"serverTokenUnavailable"` + // The effective managed settings composed from every resolved layer. Omitted when no layer + // set anything, so an unmanaged host locks nothing. + Settings any `json:"settings,omitempty"` +} + // One managed-settings channel and the document it delivered. // Experimental: ManagedSettingsLayer is part of an experimental API and may change or be // removed. @@ -6230,6 +7447,80 @@ type ManagedSettingsLayer struct { Source string `json:"source"` } +// Inputs describing the host and account whose managed remote-control policy should be +// resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention +// decision: reading this gate never becomes this runtime process's startup policy. +// Experimental: ManagedSettingsLoadRemoteControlParams is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsLoadRemoteControlParams is an internal SDK API and is not part +// of the public surface. +type ManagedSettingsLoadRemoteControlParams struct { + // The authenticated identity to resolve policy for. Omitted before sign-in, in which case + // no server layer is fetched. + AuthInfo any `json:"authInfo,omitempty"` + // Name of the embedding client, reported to the managed-settings service as `client_id` so + // it can refuse to deliver a policy this client is too old to enforce. That refusal is + // exactly what turns into an explicit `disabled` below, so a host that omits this field + // forfeits the protection. + ClientName *string `json:"clientName,omitempty"` + // A device layer supplied by the host instead of discovered from the machine. Pair it with + // `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The host's environment variables, read for cache location and policy overrides. + Environment any `json:"environment"` + // Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + // the device layer is empty; false discovers it from the machine. + HasDeviceResponse *bool `json:"hasDeviceResponse,omitempty"` + // The host's home directory, used to resolve cache and managed-file locations. + HomeDirectory string `json:"homeDirectory"` + // The host's platform, in Node's `process.platform` spelling, used to locate + // platform-specific cache and policy paths. + Platform string `json:"platform"` + // Whether a configured platform policy helper may be run to produce an enforced helper + // layer. + PolicyHelperEnabled *bool `json:"policyHelperEnabled,omitempty"` + // The policy-helper invocation reason. Defaults to sessionStart. + // Internal: PolicyHelperReason is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperReason *ManagedSettingsPolicyHelperReason `json:"policyHelperReason,omitempty"` + // Whether to run ingestion. Omit or set false to return an empty result without discovering + // or fetching policy. + SelfFetch *bool `json:"selfFetch,omitempty"` + // User agent to send with the policy fetch. + UserAgent string `json:"userAgent"` +} + +// The managed remote-control policy in force for an account, if any. An absent policy means +// the account is unmanaged for this capability, which a host reads as allowed — so absence +// here is a positive statement that no policy applies, never a stand-in for a resolution +// that failed. A resolution that cannot be completed is rejected instead. +// Experimental: ManagedSettingsLoadRemoteControlResult is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsLoadRemoteControlResult is an internal SDK API and is not part +// of the public surface. +type ManagedSettingsLoadRemoteControlResult struct { + // The account's `remoteControl` policy document. Absent when no managed policy governs + // remote control for this account. Reported as an explicit disabled policy, rather than as + // absence, when the service refused to deliver a policy this client is too old to enforce. + RemoteControl any `json:"remoteControl,omitempty"` +} + +// One diagnostic emitted while ingesting managed settings. Returned rather than logged by +// the runtime so the host decides where ingestion diagnostics go, which matters because an +// ingestion runs before a session exists to carry a log sink. +// Experimental: ManagedSettingsLogMessage is part of an experimental API and may change or +// be removed. +// Internal: ManagedSettingsLogMessage is an internal SDK API and is not part of the public +// surface. +type ManagedSettingsLogMessage struct { + // Severity of this diagnostic. + // Internal: Level is part of the SDK's internal API surface and is not intended for + // external use. + Level ManagedSettingsLogLevel `json:"level"` + // Human-readable diagnostic text. + Message string `json:"message"` +} + // Per-key lock state and provenance for `ManagedSettingsValues`, with the same field names. // Producers emit each typed key in values and meta together; both outer objects are omitted // when no typed key is set. @@ -6238,10 +7529,67 @@ type ManagedSettingsLayer struct { type ManagedSettingsMeta struct { // Lock state and provenance of `values.autoTier`. AutoTier *ManagedSettingMeta `json:"autoTier,omitempty"` + // Lock state and provenance of `values.contextTier`. + ContextTier *ManagedSettingMeta `json:"contextTier,omitempty"` + // Lock state and provenance of `values.effortLevel`. + EffortLevel *ManagedSettingMeta `json:"effortLevel,omitempty"` // Lock state and provenance of `values.model`. Model *ManagedSettingMeta `json:"model,omitempty"` } +// The client-supplied managed settings to validate and normalize. Omitting them is valid +// and yields no policy. +// Experimental: ManagedSettingsParseClientValueParams is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsParseClientValueParams is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsParseClientValueParams struct { + // The managed settings a client is supplying for a session it is about to open. Omit them + // when the client is imposing no policy of its own. + Settings any `json:"settings,omitempty"` +} + +// The accepted managed settings, reduced to the keys a client is allowed to set. +// Experimental: ManagedSettingsParseClientValueResult is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsParseClientValueResult is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsParseClientValueResult struct { + // The normalized settings. Omitted when the client supplied none. An accepted document that + // sets nothing comes back as an empty object, which is distinct from omission. + SettingsJSON any `json:"settingsJson,omitempty"` +} + +// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +// Experimental: ManagedSettingsPermissionsEvaluateResult is part of an experimental API and +// may change or be removed. +type ManagedSettingsPermissionsEvaluateResult struct { + // Managed permission policy could not be determined; every operation is denied. + FailClosed bool `json:"failClosed"` + // One verdict per input operation, in the same order, including duplicates. + Results []ManagedPermissionEvaluation `json:"results"` +} + +// The device-managed settings layer, with the sandbox floor and the load outcome a host +// needs to compose it into an effective policy. +// Experimental: ManagedSettingsReadDeviceResult is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsReadDeviceResult is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsReadDeviceResult struct { + // Whether discovery or validation failed. A host must treat this as "policy unknown" rather + // than "no policy": absent settings with this set false mean the device genuinely has none. + LoadFailed bool `json:"loadFailed"` + // Sandbox floor read from the discovered document before validation, so a document that is + // otherwise rejected can still raise the floor it declared. + SandboxFloor any `json:"sandboxFloor,omitempty"` + // Validated, canonical device-managed settings. Omitted when no device policy was + // discovered, when the discovered document failed validation, or when it validated to an + // empty object — an empty document carries no policy, and reporting it as present would + // outrank layers that do. + Settings any `json:"settings,omitempty"` +} + // Validated device-managed settings discovered before a session exists. // Experimental: ManagedSettingsReadResult is part of an experimental API and may change or // be removed. @@ -6253,6 +7601,53 @@ type ManagedSettingsReadResult struct { SettingsJSON any `json:"settingsJson,omitempty"` } +// The bypass-permissions state a host holds today, the account now signed in, and what the +// managed-policy resolution said. +// Experimental: ManagedSettingsResolveBypassDisableTransitionParams is part of an +// experimental API and may change or be removed. +// Internal: ManagedSettingsResolveBypassDisableTransitionParams is an internal SDK API and +// is not part of the public surface. +type ManagedSettingsResolveBypassDisableTransitionParams struct { + // The account signed in now. A `managed` disable pinned to a different account is lifted. + ActiveIdentity string `json:"activeIdentity"` + // The account a `managed` disable is pinned to. Omit it when the current source is not + // `managed`; it is ignored for the other sources. + CurrentManagedIdentity *string `json:"currentManagedIdentity,omitempty"` + // Which layer currently disables bypass mode. Omit it when nothing does. + // Internal: CurrentSource is part of the SDK's internal API surface and is not intended for + // external use. + CurrentSource *ManagedSettingsBypassDisableSource `json:"currentSource,omitempty"` + // What the resolution said about bypass mode. Send `unknown` rather than omitting the field + // when there is no verdict. + // Internal: Policy is part of the SDK's internal API surface and is not intended for + // external use. + Policy ManagedSettingsBypassPolicyResolution `json:"policy"` +} + +// The bypass-permissions state a host should hold after the resolution, and what it must do +// to get there. +// Experimental: ManagedSettingsResolveBypassDisableTransitionResult is part of an +// experimental API and may change or be removed. +// Internal: ManagedSettingsResolveBypassDisableTransitionResult is an internal SDK API and +// is not part of the public surface. +type ManagedSettingsResolveBypassDisableTransitionResult struct { + // The account the returned `managed` source is pinned to. Store it alongside `source`; the + // next call needs it to decide whether an account switch lifts the disable. + ManagedIdentity *string `json:"managedIdentity,omitempty"` + // The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly + // as it is, which is not the same as being told to store `false`. + SetDisabledState *bool `json:"setDisabledState,omitempty"` + // Which layer disables bypass mode after this resolution. Omitted when none does, which is + // what a lifted disable looks like. + // Internal: Source is part of the SDK's internal API surface and is not intended for + // external use. + Source *ManagedSettingsBypassDisableSource `json:"source,omitempty"` + // Whether a bypass-permissions session already running must be turned off. True only when + // this resolution newly disables bypass mode, so a host that is already compliant is not + // interrupted. + SuppressRuntimeAllowAll bool `json:"suppressRuntimeAllowAll"` +} + // Effective enterprise managed settings and contributing channels. Session events report // applied policy; sessionless resolve reports an account/device snapshot, and compose // reports a non-applying preview of candidate documents. Device values take precedence over @@ -6262,16 +7657,18 @@ type ManagedSettingsReadResult struct { // Experimental: ManagedSettingsResolvedData is part of an experimental API and may change // or be removed. type ManagedSettingsResolvedData struct { - // Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. - // Deny-wins across layers, and forced on when `failClosed` is true. + // Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") + // mode for this session. Deny-wins across layers; an unresolved policy does not force this + // on by itself. BypassPermissionsDisabled bool `json:"bypassPermissionsDisabled"` // Whether a session-local permissions layer injected by the SDK host was present ClientManaged *bool `json:"clientManaged,omitempty"` // Whether an actual device MDM/plist/registry/file managed-settings layer was present DeviceManaged bool `json:"deviceManaged"` - // Whether managed policy could not be determined (e.g. a failed server fetch) and the - // session fell back to the fail-closed restriction. When true, restrictions such as - // disabling bypass-permissions are enforced even though `settings` may be absent. + // Whether managed policy could not be determined (e.g. a failed server fetch) and + // unresolved-policy safeguards remain active. This does not by itself disable + // bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy + // restriction. FailClosed bool `json:"failClosed"` // The setting keys under enterprise management in the effective managed settings (e.g. // `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. @@ -6279,6 +7676,10 @@ type ManagedSettingsResolvedData struct { // Whether at least two managed sources supplied permission allowlists, so enforcement // intersects them and the flattened settings payload omits `permissions.allow`. PermissionsAllowIntersected *bool `json:"permissionsAllowIntersected,omitempty"` + // Reusable retained managed permission policy for managedSettings.permissions.evaluate, + // including source composition and session-local injection. Provided by live session + // snapshots; absent in older events. Refresh the context when managed policy changes. + PermissionsContext *ManagedPermissionsContext `json:"permissionsContext,omitempty"` // Whether the policy-helper managed-settings layer was present. The policy helper is the // weakest channel: it fills keys no enterprise source set and can never replace one. PolicyHelperManaged *bool `json:"policyHelperManaged,omitempty"` @@ -6298,6 +7699,54 @@ type ManagedSettingsResolvedData struct { Source ManagedSettingsResolvedSource `json:"source"` } +// The credential and environment to evaluate the device-channel sign-in pin against. +// Experimental: ManagedSettingsResolveDeviceForceLoginOrgsGateParams is part of an +// experimental API and may change or be removed. +// Internal: ManagedSettingsResolveDeviceForceLoginOrgsGateParams is an internal SDK API and +// is not part of the public surface. +type ManagedSettingsResolveDeviceForceLoginOrgsGateParams struct { + // The authenticated identity to judge. Omitted when signed out, which is the case the + // device channel exists to serve: it can refuse a first sign-in before any credential + // exists. + AuthInfo any `json:"authInfo,omitempty"` + // The host's environment variables. Read for the variables that would make an identity's + // membership snapshot forgeable, so a credential whose provenance cannot be trusted is + // refused rather than accepted. + Environment any `json:"environment"` +} + +// The managed-settings layers to compose into an effective policy. Every layer is optional; +// omitting all of them yields no effective policy. +// Experimental: ManagedSettingsResolveEffectiveValueParams is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveEffectiveValueParams is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveEffectiveValueParams struct { + // The device sandbox floor, folded into the device layer under `sandbox` before composition. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // The device layer: native MDM and managed-file settings describing the machine rather than + // the account. + Mdm any `json:"mdm,omitempty"` + // The policy-helper layer, an enforced channel sourced from a platform policy helper + // process. + PolicyHelper any `json:"policyHelper,omitempty"` + // The account's server-delivered org policy, as returned by a managed-settings fetch. + // Omitted before sign-in or when the fetch has not landed. + Server any `json:"server,omitempty"` +} + +// The effective managed policy composed from the supplied layers. +// Experimental: ManagedSettingsResolveEffectiveValueResult is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveEffectiveValueResult is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveEffectiveValueResult struct { + // The composed effective managed settings. Omitted when no layer sets anything, so an + // unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an + // advisory server force-on was dropped because this host cannot run the sandbox. + SettingsJSON any `json:"settingsJson,omitempty"` +} + // Experimental: ManagedSettingsResolveRequest is part of an experimental API and may change // or be removed. type ManagedSettingsResolveRequest struct { @@ -6310,6 +7759,9 @@ type ManagedSettingsResolveRequest struct { // Opaque account identifier returned by `account.getAllUsers`. When omitted, the current // account is used, or device policy only when no account is signed in. SelectionID *string `json:"selectionId,omitempty"` + // Working directory used to run an organization policy helper. When omitted, sessionless + // resolution does not run the helper. + WorkingDirectory *string `json:"workingDirectory,omitempty"` } // Effective enterprise managed settings for an account, resolved without a session. @@ -6330,6 +7782,11 @@ type ManagedSettingsResolveResult struct { Layers []ManagedSettingsLayer `json:"layers"` // Per-key lock state and provenance for the entries in `values`, using the same key names. Meta *ManagedSettingsMeta `json:"meta,omitempty"` + // Reusable source-composed permission policy for managedSettings.permissions.evaluate. + // Unlike resolved.settings.permissions, this retains every source's allowlist and + // default-prompt semantics. Refresh through resolve when account/device policy changes. + // Absent on runtimes that do not support permission evaluation. + PermissionsContext *ManagedPermissionsContext `json:"permissionsContext,omitempty"` // Effective managed settings from the device and account (server) channels, in the same // shape as `session.managedSettings.get`, excluding session-local injection. Resolved ManagedSettingsResolvedData `json:"resolved"` @@ -6340,6 +7797,197 @@ type ManagedSettingsResolveResult struct { Values *ManagedSettingsValues `json:"values,omitempty"` } +// Inputs describing the host and account a startup policy resolution should run for. +// Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is +// retained for this runtime process. +// Experimental: ManagedSettingsResolveStartupPolicyParams is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveStartupPolicyParams is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveStartupPolicyParams struct { + // The authenticated identity to resolve policy for. Omitted before sign-in, in which case + // no server layer is fetched and the sign-in pin is evaluated against no credential. + AuthInfo any `json:"authInfo,omitempty"` + // Whether to ignore a cached server policy when reading, forcing the resolution to come + // from a live fetch. + BypassCacheRead *bool `json:"bypassCacheRead,omitempty"` + // Name of the embedding client, reported to the managed-settings service as `client_id` so + // it can refuse to deliver a policy this client is too old to enforce. + ClientName *string `json:"clientName,omitempty"` + // A device layer supplied by the host instead of discovered from the machine. Pair it with + // `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The host's environment variables, read for cache location, policy overrides, and the + // variables that would make a membership snapshot forgeable. + Environment any `json:"environment"` + // Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + // the device layer is empty; false discovers it from the machine. + HasDeviceResponse *bool `json:"hasDeviceResponse,omitempty"` + // The host's home directory, used to resolve cache and managed-file locations. + HomeDirectory string `json:"homeDirectory"` + // The host's platform, in Node's `process.platform` spelling, used to locate + // platform-specific cache and policy paths. + Platform string `json:"platform"` + // Whether a configured platform policy helper may be run to produce an enforced helper + // layer. + PolicyHelperEnabled *bool `json:"policyHelperEnabled,omitempty"` + // The policy-helper invocation reason. Defaults to sessionStart. + // Internal: PolicyHelperReason is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperReason *ManagedSettingsPolicyHelperReason `json:"policyHelperReason,omitempty"` + // Directory the policy helper runs in when this resolution is not owned by a registered + // session. A host resolving policy before its session exists must pass this, or a + // directory-sensitive helper judges the wrong repository. + PolicyHelperWorkingDirectory *string `json:"policyHelperWorkingDirectory,omitempty"` + // Whether to retain the resolved policy as this runtime process's startup policy, so later + // work in the process enforces it. Set false to resolve without side effects, which is what + // a protocol host wants before session creation: its sessions apply the complete policy + // through the normal lifecycle, and retaining here would let a readiness credential affect + // unrelated sessions. The returned verdict is identical either way — this decides only + // whether the process keeps it. + RetainAndApply bool `json:"retainAndApply"` + // Whether to run ingestion. Omit or set false to return an empty result without discovering + // or fetching policy. + SelfFetch *bool `json:"selfFetch,omitempty"` + // How this resolution may use the on-disk server-policy cache. Defaults to the runtime's + // own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two + // express the same decision and accepting both would leave the caller unsure which one the + // runtime honored. + // Internal: ServerPolicyCacheMode is part of the SDK's internal API surface and is not + // intended for external use. + ServerPolicyCacheMode *ManagedSettingsServerPolicyCacheMode `json:"serverPolicyCacheMode,omitempty"` + // The session whose credential store, working directory and client kind the resolution + // should use. Omit it when no session exists yet and the process-wide store applies. A + // resolution whose session names a credential other than `authInfo` is returned but not + // retained, so a stale sign-in cannot apply policy for an account that has already been + // switched away from. + SessionID *string `json:"sessionId,omitempty"` + // User agent to send with the policy fetch. + UserAgent string `json:"userAgent"` +} + +// The startup policy a resolution composed, the per-layer outcome flags a host needs to +// decide how much to trust it, and the enterprise sign-in verdict for the credential it ran +// against. The flags are reported rather than folded into the settings because a host must +// distinguish an unmanaged device from a managed device whose policy could not be +// confirmed, and apply its fail-closed gates in the second case. +// Experimental: ManagedSettingsResolveStartupPolicyResult is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveStartupPolicyResult is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveStartupPolicyResult struct { + // Advisory minimum client version from a successful server response. + ClientUpdateRequested *string `json:"clientUpdateRequested,omitempty"` + // The server refused to deliver a policy because this client is too old to enforce it, + // carrying the user-facing sentence describing the refusal. No retry will help; the remedy + // is a client update. + ClientUpdateRequired *string `json:"clientUpdateRequired,omitempty"` + // The device layer could not be read, so it is unconfirmed rather than known-absent. + DeviceLoadFailed bool `json:"deviceLoadFailed"` + // The device layer discovered from the machine, when one exists. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The sandbox floor contributed by the device layer. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // The enterprise sign-in verdict for the credential this resolution ran against, evaluated + // over the effective policy so a server-delivered pin is honored alongside a device one. + // Computed on every resolution, including one that was not retained, so a host that + // declines to apply policy still cannot proceed past a pin. + // Internal: ForceLoginOrgs is part of the SDK's internal API surface and is not intended + // for external use. + ForceLoginOrgs ForceLoginOrgsDecision `json:"forceLoginOrgs"` + // A managed policy is known to apply to this host, from a discovered source or a resolved + // document. + ManagedPolicyPresent bool `json:"managedPolicyPresent"` + // The permissions layer specifically could not be confirmed, so permission gates apply + // their fail-closed posture. + PermissionPolicyUndetermined bool `json:"permissionPolicyUndetermined"` + // The policy helper was configured but could not be run, or its output could not be read. + PolicyHelperLoadFailed bool `json:"policyHelperLoadFailed"` + // The layer produced by the platform policy helper, when one ran. + PolicyHelperResponse any `json:"policyHelperResponse,omitempty"` + // Some layer of the policy could not be confirmed, so its absence must not be read as + // permission. Folds in a failed server fetch as well as an unreadable device layer. + PolicyUndetermined bool `json:"policyUndetermined"` + // The sandbox was enabled because policy could not be confirmed rather than because an + // administrator asked for it. Lets a host explain a sandbox the user did not configure. + SandboxEnabledByUndeterminedPolicy bool `json:"sandboxEnabledByUndeterminedPolicy"` + // The effective sandbox floor composed across every layer, which a host must apply rather + // than its own default. + SandboxFloor any `json:"sandboxFloor,omitempty"` + // The server fetch failed and no cached entry stood in for it, so the server layer is + // unconfirmed and fail-closed gates apply. + ServerFetchFailed bool `json:"serverFetchFailed"` + // How the current runtime resolved the server layer. + // Internal: ServerResolution is part of the SDK's internal API surface and is not intended + // for external use. + ServerResolution ManagedSettingsServerPolicyResolution `json:"serverResolution"` + // The account's server-delivered policy, when one was resolved. + ServerResponse any `json:"serverResponse,omitempty"` + // Telemetry describing which layers answered and how, for the host to report alongside its + // own startup events. + Telemetry any `json:"telemetry"` + // Warnings raised while resolving, in the order they occurred. + Warnings []string `json:"warnings"` +} + +// The managed layers to retain as this process's startup policy, with the outcome of +// fetching each one. +// Experimental: ManagedSettingsRetainPolicyParams is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsRetainPolicyParams is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsRetainPolicyParams struct { + // Whether the device load failed. Report it honestly, for the same reason as + // `serverFetchFailed`. + DeviceLoadFailed bool `json:"deviceLoadFailed"` + // The device/MDM policy layer. + DeviceResponse any `json:"deviceResponse,omitempty"` + // Sandbox floor declared by the device layer, carried separately so a document that failed + // validation can still raise the floor. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // Whether the device sandbox intent is unreadable independently of its other settings. + DeviceSandboxUndetermined bool `json:"deviceSandboxUndetermined"` + // Whether a device policy source demonstrably exists. This, not a read error, is the + // evidence a device is managed, so a fail-closed policy gates on it. + DeviceSourceFound bool `json:"deviceSourceFound"` + // Whether any managed policy source exists, independently of fetch failures. + ManagedPolicyPresent bool `json:"managedPolicyPresent"` + // Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this + // flag. + PermissionPolicyUndetermined bool `json:"permissionPolicyUndetermined"` + // The policy helper's response: the third managed layer that a process owning its startup + // policy resolves. It is retained with the other two so that every ambient read in this + // process, including the mutation guards and the governed marketplace allowlist that the + // `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning + // process omits it, because it resolves a helper per session against that session's working + // directory. + PolicyHelperResponse any `json:"policyHelperResponse,omitempty"` + // Preserve the retained server layer during a device-only resolution. + PreserveServerState bool `json:"preserveServerState"` + // Whether uncertainty alone enabled the shared sandbox floor. + SandboxEnabledByUndeterminedPolicy bool `json:"sandboxEnabledByUndeterminedPolicy"` + // Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply + // this flag. + SandboxFloorUndetermined bool `json:"sandboxFloorUndetermined"` + // Whether the server fetch failed. Report it honestly: true keeps the already-retained + // server layer rather than replacing it with an absent one. + ServerFetchFailed bool `json:"serverFetchFailed"` + // Whether a required fresh server-policy confirmation failed. + ServerForcedRefreshFailure bool `json:"serverForcedRefreshFailure"` + // The resolved server policy. A known source can lack a response after a forced-refresh + // failure. + ServerResponse any `json:"serverResponse,omitempty"` + // Whether the server policy source exists, even when its response is unavailable. + ServerSourceFound bool `json:"serverSourceFound"` + // Shared server/device sandbox floor, excluding session-local helper policy. + SharedSandboxFloor any `json:"sharedSandboxFloor,omitempty"` +} + +// Experimental: ManagedSettingsRetainPolicyResult is part of an experimental API and may +// change or be removed. +type ManagedSettingsRetainPolicyResult struct { +} + // The authoring JSON schema for managed settings recognized by this runtime. // Experimental: ManagedSettingsSchemaResult is part of an experimental API and may change // or be removed. @@ -6387,8 +8035,14 @@ type ManagedSettingsValidateResult struct { type ManagedSettingsValues struct { // Managed Auto routing preference, used when the selected model is `auto`. AutoTier *AutoTier `json:"autoTier,omitempty"` - // Managed default model identifier, as configured. New sessions start with it; it can name - // a model the account cannot use, so hosts match it against the listed models. + // Managed context-tier default for the managed concrete model. + ContextTier *ContextTier `json:"contextTier,omitempty"` + // Managed reasoning-effort default for the managed concrete model. The runtime clamps it to + // an entitled effort when model availability is known. + EffortLevel *string `json:"effortLevel,omitempty"` + // Managed default model identifier. When model availability was resolved, aliases and + // family names are projected to a concrete available model ID; otherwise the configured + // value is returned. Model *string `json:"model,omitempty"` } @@ -6787,9 +8441,53 @@ type MCPConfigUpdateRequest struct { type MCPConfigUpdateResult struct { } +// Effective MCP configuration entry. Configuration enablement is distinct from the optional +// live observation. +// Experimental: MCPConfiguredServer is part of an experimental API and may change or be +// removed. +type MCPConfiguredServer struct { + // Human-readable display name supplied by configuration. + DisplayName *string `json:"displayName,omitempty"` + // Whether this configured server is enabled after session configuration and policy + // filtering. + Enabled bool `json:"enabled"` + // Observed state from an already materialized matching server. Omitted when no live graph + // has this configured server; it never determines configuration enablement. + Live MCPConfiguredServerState `json:"live"` + // Server name (config key) + Name string `json:"name"` + // Configuration provenance: user, workspace, plugin, builtin, or managed. + Source *MCPServerSource `json:"source,omitempty"` + // Plugin name that provided this server, when source is plugin. + SourcePlugin *string `json:"sourcePlugin,omitempty"` + // Plugin version that provided this server, when source is plugin. + SourcePluginVersion *string `json:"sourcePluginVersion,omitempty"` +} + +// Effective MCP configuration with optional live observations from matching already +// materialized servers. +// Experimental: MCPConfiguredServerList is part of an experimental API and may change or be +// removed. +type MCPConfiguredServerList struct { + // Effective configured MCP servers. + Servers []MCPConfiguredServer `json:"servers"` +} + +// Observational state for a matching already materialized MCP server. +// Experimental: MCPConfiguredServerState is part of an experimental API and may change or +// be removed. +type MCPConfiguredServerState struct { + // Observed connection error, when the materialized server failed. + Error *string `json:"error,omitempty"` + // Observed connection status. This is not a configuration or readiness guarantee. + Status MCPServerStatus `json:"status"` +} + // Credential-free authentication identity used to configure GitHub MCP. // Experimental: MCPConfigureGitHubRequest is part of an experimental API and may change or // be removed. +// Internal: MCPConfigureGitHubRequest is an internal SDK API and is not part of the public +// surface. type MCPConfigureGitHubRequest struct { // Opaque runtime auth info for GitHub MCP configuration. Marked internal: an in-process // runtime shape (configureGitHubMcp is a no-op over the wire). @@ -7598,6 +9296,17 @@ type MCPIsServerRunningResult struct { Running bool `json:"running"` } +// Names of the MCP servers the runtime supplies itself. +// Experimental: MCPListBuiltinServerNamesResult is part of an experimental API and may +// change or be removed. +// Internal: MCPListBuiltinServerNamesResult is an internal SDK API and is not part of the +// public surface. +type MCPListBuiltinServerNamesResult struct { + // Every built-in server name. A host disabling the built-ins wholesale suppresses exactly + // this set. + Names []string `json:"names"` +} + // Server name whose tool list should be returned. // Experimental: MCPListToolsRequest is part of an experimental API and may change or be // removed. @@ -8510,6 +10219,8 @@ type MCPPromptsListResult struct { // Registration parameters for an external MCP client. // Experimental: MCPRegisterExternalClientRequest is part of an experimental API and may // change or be removed. +// Internal: MCPRegisterExternalClientRequest is an internal SDK API and is not part of the +// public surface. type MCPRegisterExternalClientRequest struct { // In-process MCP Client instance. Marked internal: cannot be serialized across the JSON-RPC // boundary. @@ -8530,8 +10241,80 @@ type MCPRegisterExternalClientRequest struct { Transport any `json:"transport"` } +// Registry search to abandon. +// Experimental: MCPRegistryCancelRequest is part of an experimental API and may change or +// be removed. +// Internal: MCPRegistryCancelRequest is an internal SDK API and is not part of the public +// surface. +type MCPRegistryCancelRequest struct { + // Request ID from `mcp.registry.allocateRequestId` that the search uses. + RequestID int64 `json:"requestId"` +} + +// Whether the cancel reached a live search. +// Experimental: MCPRegistryCancelResult is part of an experimental API and may change or be +// removed. +// Internal: MCPRegistryCancelResult is an internal SDK API and is not part of the public +// surface. +type MCPRegistryCancelResult struct { + // True when the cancel stopped a running search. False for unknown or reclaimed IDs, + // completed or canceled searches, and unused reservations. The cancel releases an unused + // reservation. + Canceled bool `json:"canceled"` +} + +// Request id naming a cancellable registry search. +// Experimental: MCPRegistryRequestIDResult is part of an experimental API and may change or +// be removed. +// Internal: MCPRegistryRequestIDResult is an internal SDK API and is not part of the public +// surface. +type MCPRegistryRequestIDResult struct { + // Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. + // Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + RequestID int64 `json:"requestId"` +} + +// Registry search terms, the credential to search under, and the request id that makes the +// search cancellable. +// Experimental: MCPRegistrySearchRequest is part of an experimental API and may change or +// be removed. +// Internal: MCPRegistrySearchRequest is an internal SDK API and is not part of the public +// surface. +type MCPRegistrySearchRequest struct { + // The credential the search runs under, carried opaquely. Hosts usually send + // credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a + // token, while `env` and `gh-cli` identities can use a token embedded in the request first. + AuthInfo any `json:"authInfo"` + // Maximum number of servers to return. + Limit int64 `json:"limit"` + // Free-text query. Omitted or empty asks the registry for its top servers rather than + // searching. A value that is not a string is refused. + Query *string `json:"query,omitempty"` + // Repository used for the policy lookup, as `owner/name`. The policy selects the registry + // URL and whether the user token goes to the registry. The registry receives this + // repository only when the policy entry lists it as required context. A value that is not a + // string is refused. + Repository *string `json:"repository,omitempty"` + // Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, + // or canceled IDs and IDs that another search or request already uses. + RequestID int64 `json:"requestId"` +} + +// Servers selected from the registry response. +// Experimental: MCPRegistrySearchResult is part of an experimental API and may change or be +// removed. +// Internal: MCPRegistrySearchResult is an internal SDK API and is not part of the public +// surface. +type MCPRegistrySearchResult struct { + // The server objects, carried opaquely. The runtime follows pages, keeps the newest entry + // per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub + // stars. Each server object remains unchanged because the registry owns that shape. + Servers any `json:"servers"` +} + // In-process MCP reload configuration. // Experimental: MCPReloadConfig is part of an experimental API and may change or be removed. +// Internal: MCPReloadConfig is an internal SDK API and is not part of the public surface. type MCPReloadConfig struct { ActiveGitHubToken *string `json:"activeGitHubToken,omitempty"` // Server names the CLI enabled for this session via `--enable-mcp-server`. @@ -8552,6 +10335,8 @@ type MCPReloadConfig struct { // Opaque MCP reload configuration. // Experimental: MCPReloadWithConfigRequest is part of an experimental API and may change or // be removed. +// Internal: MCPReloadWithConfigRequest is an internal SDK API and is not part of the public +// surface. type MCPReloadWithConfigRequest struct { // Opaque runtime MCP reload configuration. Marked internal: an in-process runtime shape // (reloadMcpServers throws over the wire). @@ -8962,6 +10747,9 @@ type MCPServer struct { // Connection status: connected, failed, needs-auth, pending, disabled, stopped, or // not_configured Status MCPServerStatus `json:"status"` + // Configured URL for an HTTP/SSE server, regardless of configuration source. Omitted for + // local and in-memory servers. + URL *string `json:"url,omitempty"` } // Set to `true` to use defaults, or provide an object with additional auth or OIDC settings. @@ -9054,6 +10842,8 @@ func (MCPServerConfigHTTP) mcpServerConfig() {} // In-process MCP server configuration used by embedded SDK clients. // Experimental: MCPServerConfigMemory is part of an experimental API and may change or be // removed. +// Internal: MCPServerConfigMemory is an internal SDK API and is not part of the public +// surface. type MCPServerConfigMemory struct { // Configuration warnings recorded while loading the server. ConfigWarnings []string `json:"configWarnings,omitzero"` @@ -9174,6 +10964,38 @@ type MCPSetEnvValueModeResult struct { Mode MCPSetEnvValueModeDetails `json:"mode"` } +// The session tool filters that decide whether the session still has a shell to run `gh` +// with. +// Experimental: MCPShouldExcludeGitHubToolsRequest is part of an experimental API and may +// change or be removed. +// Internal: MCPShouldExcludeGitHubToolsRequest is an internal SDK API and is not part of +// the public surface. +type MCPShouldExcludeGitHubToolsRequest struct { + // The session's tool allowlist, when it set one. Omitted means the session constrains + // nothing this way. + AvailableTools []string `json:"availableTools,omitzero"` + // The session's tool denylist, when it set one. Omitted means the session constrains + // nothing this way. + ExcludedTools []string `json:"excludedTools,omitzero"` + // How the allowlist and denylist combine when both are set. Omitted means the default every + // session gets, so a caller that never chose a precedence is answered as its sessions + // behave. + ToolFilterPrecedence *OptionsUpdateToolFilterPrecedence `json:"toolFilterPrecedence,omitempty"` +} + +// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by +// the request. +// Experimental: MCPShouldExcludeGitHubToolsResult is part of an experimental API and may +// change or be removed. +// Internal: MCPShouldExcludeGitHubToolsResult is an internal SDK API and is not part of the +// public surface. +type MCPShouldExcludeGitHubToolsResult struct { + // True only when both halves hold: the session's filters still reach the platform shell + // tool, and the host actually has the `gh` those tools would be replaced by. Feed it + // straight back as the `excludeGhReplaceableTools` build option. + ExcludeGhReplaceableTools bool `json:"excludeGhReplaceableTools"` +} + // Concrete configuration file containing an MCP server declaration. // Experimental: MCPSourceFile is part of an experimental API and may change or be removed. type MCPSourceFile struct { @@ -9300,6 +11122,8 @@ type MCPUninstallPlan struct { // Server name identifying the external client to remove. // Experimental: MCPUnregisterExternalClientRequest is part of an experimental API and may // change or be removed. +// Internal: MCPUnregisterExternalClientRequest is an internal SDK API and is not part of +// the public surface. type MCPUnregisterExternalClientRequest struct { // Server name of the external client to unregister ServerName string `json:"serverName"` @@ -9346,10 +11170,15 @@ type MetadataContextHeaviestMessagesResult struct { // Experimental: MetadataContextInfoRequest is part of an experimental API and may change or // be removed. type MetadataContextInfoRequest struct { - // Maximum output tokens allowed by the target model. Pass 0 if unknown. + // Requested output allowance to reserve against the combined context ceiling. Pass 0 to + // resolve the session's request cap, falling back to the model's advertised output limit. OutputTokenLimit int64 `json:"outputTokenLimit"` - // Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default. + // Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from + // the session. PromptTokenLimit int64 `json:"promptTokenLimit"` + // Provider owning selectedModel. Omit to use the current provider for the current model, or + // deterministic legacy lookup for a different model. + ProviderID *string `json:"providerId,omitempty"` // Model identifier used for tokenization. Omit to use the session default. Used both for // token counting and to compute display values. SelectedModel *string `json:"selectedModel,omitempty"` @@ -9538,6 +11367,11 @@ type Model struct { SupportedContextTiers []string `json:"supportedContextTiers,omitzero"` // Supported reasoning effort levels (only present if model supports reasoning effort) SupportedReasoningEfforts []string `json:"supportedReasoningEfforts,omitzero"` + // Model vendor as the Copilot API reports it, for example "Anthropic" or "Azure OpenAI". + // Open vocabulary, passed through unchanged. It can name the vendor that serves the model + // instead of the one that built it, or a label that is not a vendor, such as + // "Experimental". Absent when the Copilot API reports no vendor. + Vendor *string `json:"vendor,omitempty"` // Warnings the service published for this model, such as a deprecated client version. // Present only when the service published at least one warning. The model remains usable; // hosts should surface these as advisory rather than blocking. @@ -9579,6 +11413,9 @@ type ModelApplyStartupOverlayRequest struct { RepoContextTier *string `json:"repoContextTier,omitempty"` // Model selected by repository settings, when configured. RepoModel *string `json:"repoModel,omitempty"` + // Provider owning the repository-selected model. Omitted repository provider identity + // retains legacy bare-model behavior. + RepoModelProviderID *string `json:"repoModelProviderId,omitempty"` // Reasoning effort selected by repository settings, when configured. RepoReasoningEffort *string `json:"repoReasoningEffort,omitempty"` // Model required by server-managed policy, when configured. @@ -9809,6 +11646,86 @@ type ModelCapabilitiesSupports struct { Vision *bool `json:"vision,omitempty"` } +// Experimental: ModelClearStartupSeedRequest is part of an experimental API and may change +// or be removed. +// Internal: ModelClearStartupSeedRequest is an internal SDK API and is not part of the +// public surface. +type ModelClearStartupSeedRequest struct { + ExpectedModel string `json:"expectedModel"` + // Provider captured with the startup seed; omission matches only an unqualified seed. + ExpectedProviderID *string `json:"expectedProviderId,omitempty"` +} + +// Experimental: ModelClearStartupSeedResult is part of an experimental API and may change +// or be removed. +// Internal: ModelClearStartupSeedResult is an internal SDK API and is not part of the +// public surface. +type ModelClearStartupSeedResult struct { + Cleared bool `json:"cleared"` +} + +// Host presentation state the reasoning-summaries policy depends on. +// Experimental: ModelGetReasoningSummariesRequest is part of an experimental API and may +// change or be removed. +type ModelGetReasoningSummariesRequest struct { + // The host's persisted `showReasoning` user setting, omitted when unset. + PersistedShowReasoning *bool `json:"persistedShowReasoning,omitempty"` + // Whether the host is currently showing reasoning summaries. Defaults to false. + SummariesVisible *bool `json:"summariesVisible,omitempty"` +} + +// Reasoning-summaries presentation policy for the session's current model. +// Experimental: ModelGetReasoningSummariesResult is part of an experimental API and may +// change or be removed. +type ModelGetReasoningSummariesResult struct { + // Whether the supplied `persistedShowReasoning` setting only restates the model default. + // This reports a redundancy, not a standing instruction to delete the setting: it stays + // true for as long as the setting and the model default agree, including for a user who + // later chose that value deliberately. It exists for a one-time migration of a legacy + // setting written before the model default made it redundant, so a host that acts on it + // owns the cleanup and must gate it behind its own persisted `done` marker, delete only a + // setting whose value still matches the one it read, and never repeat the deletion on a + // later launch. Under an off-by-default reasoning-summaries experiment an explicit + // `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an + // ungated host would keep deleting that opt-in and hide summaries again on every launch. + ClearRedundantSetting bool `json:"clearRedundantSetting"` + // Whether the session's reasoning-summaries experiment assignment has settled. False means + // this read does not wait for a pending assignment and reports the experiment-derived + // fields conservatively: `showHiddenHint` is false and `visibility` falls back to + // `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the + // assigned answer re-reads until this is true. + ExperimentSettled bool `json:"experimentSettled"` + // Whether the selected model shows reasoning summaries by default. + ModelDefaultShowsSummaries bool `json:"modelDefaultShowsSummaries"` + // False until the session has a model catalog and a selected model. This read never + // resolves the catalog itself, and the runtime emits no readiness notification, so + // repeating this call alone leaves `ready` false indefinitely on a session that has neither + // listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it + // resolves and caches the catalog for the session, so a successful return means the next + // read is ready. The exception is a session that resolves models without a Copilot catalog, + // that is a BYOK registry or an alternate provider: `session.model.list` returns an empty + // list without caching a catalog, so `ready` stays false and this policy is unavailable + // there. While false, every model-policy field is false and `visibility` is omitted; + // `experimentSettled` is independent of readiness and still reports the assignment state. + Ready bool `json:"ready"` + // Whether turns on this session produce reasoning summaries, honouring an explicit session + // reasoning-summary override. + SessionShowsSummaries bool `json:"sessionShowsSummaries"` + // Whether to show the hint that reasoning summaries are hidden. Always false while + // `experimentSettled` is false. + ShowHiddenHint bool `json:"showHiddenHint"` + // Whether the selected model emits reasoning headers. + ShowReasoningHeaders bool `json:"showReasoningHeaders"` + // Default reasoning visibility, and only meaningful once `ready` is true: false when the + // session produces no summaries, else the persisted setting, else the experiment's default. + // While `ready` is true it is omitted only when all three are unavailable, that is when the + // session produces summaries, no `persistedShowReasoning` was supplied, and + // `experimentSettled` is false. While `ready` is false there is no model policy to report + // and this field is always omitted, so an absent value alone does not imply a pending + // experiment. + Visibility *bool `json:"visibility,omitempty"` +} + // List of Copilot models available to the resolved user, including capabilities and billing // metadata. // Experimental: ModelList is part of an experimental API and may change or be removed. @@ -10270,12 +12187,17 @@ type ModelSwitchToRequest struct { ModelCapabilities *ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"` // Settings scope used when persisting the selected model. ModelChangeScope *string `json:"modelChangeScope,omitempty"` - // Model selection id to switch to, as returned by `list`. A bare id (e.g. - // `claude-sonnet-4.6`) names a Copilot (CAPI) model; a provider-qualified id - // (`provider/id`, e.g. `acme/claude-sonnet`) targets a registry BYOK model. + // Model id to switch to, as returned by `list`. Include providerId to select an exact + // catalog entry when providers share the id. Without providerId, a bare id retains + // incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. + // `acme/claude-sonnet`) targets a BYOK model. ModelID string `json:"modelId"` // Optional settings context and explicit-override flags used to persist a picker selection. PickerPersistence *ModelPickerPersistenceRequest `json:"pickerPersistence,omitempty"` + // Provider id from the selected list entry's provider reference. Selects this exact + // provider/model pair; an unavailable pair fails rather than using another provider. Omit + // for deterministic legacy bare-model selection. + ProviderID *string `json:"providerId,omitempty"` // Reasoning effort level to use for the model. CAPI values are model-defined and validated // against the selected model; BYOK providers may define additional values. "none" disables // reasoning. Pass null to clear any session effort override and fall back to the model's @@ -10360,6 +12282,8 @@ type ModeSetRequest struct { PlanModel *string `json:"planModel,omitempty"` // Whether a dedicated plan model is configured. PlanModelConfigured *bool `json:"planModelConfigured,omitempty"` + // Provider owning planModel. Omit for legacy bare-model selection. + PlanModelProviderID *string `json:"planModelProviderId,omitempty"` // Reasoning effort to use with the dedicated plan model. PlanReasoningEffort *string `json:"planReasoningEffort,omitempty"` // Whether leaving plan mode should restore the session's previous model. @@ -10529,6 +12453,39 @@ type OptionsUpdateAdditionalContentExclusionPolicyRuleSource struct { Type string `json:"type"` } +// External tool call of the session or one of its sub-agents that is still waiting for +// session.tools.handlePendingToolCall. +// Experimental: PendingExternalToolRequest is part of an experimental API and may change or +// be removed. +type PendingExternalToolRequest struct { + // Sub-agent instance identifier (the envelope agentId of its events) of the agent that + // issued the call; absent for calls issued by the root agent + AgentID *string `json:"agentId,omitempty"` + // Arguments to pass to the external tool + Arguments any `json:"arguments,omitempty"` + // Stable identity of the provider that offered the tool, for hosts that route + // extension-owned tools by provider + ProviderID *string `json:"providerId,omitempty"` + // Request ID to pass to session.tools.handlePendingToolCall + RequestID string `json:"requestId"` + // Tool call ID assigned to this external tool invocation + ToolCallID string `json:"toolCallId"` + // Name of the external tool to invoke + ToolName string `json:"toolName"` +} + +// External tool calls still waiting for a result. +// Experimental: PendingExternalToolRequestList is part of an experimental API and may +// change or be removed. +type PendingExternalToolRequestList struct { + // External tool calls of the session and its sub-agents that + // session.tools.handlePendingToolCall would still accept, in the order they were requested. + // Includes calls that were pending when the session was last suspended and resumed with + // pending work continued, so a host that did not observe the original + // external_tool.requested event can answer them. + Items []PendingExternalToolRequest `json:"items"` +} + // Pending permission prompt reconstructed from event history, with request ID and // user-facing prompt details. // Experimental: PendingPermissionRequest is part of an experimental API and may change or @@ -11370,6 +13327,12 @@ type PermissionRecoveryData struct { // Policy selected from the current client's response capability; mode or client changes may // update it during recovery OnBlocked PermissionRecoveryOnBlocked `json:"onBlocked"` + // Subagent identifier that owns this recovery episode when the request was delegated + // through a parent permission service + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + // Root or child execution-session identifier that owns this recovery episode; omitted for + // legacy snapshots + OwnerSessionID *string `json:"ownerSessionId,omitempty"` // Controlled reason for the latest episode transition Reason PermissionRecoveryReason `json:"reason"` // Current lifecycle state of the recovery episode @@ -11483,6 +13446,32 @@ type PermissionsConfigureResult struct { Success bool `json:"success"` } +// The verbatim managed `permissions` slice to interpret. +// Experimental: PermissionsEvaluateManagedPolicyParams is part of an experimental API and +// may change or be removed. +// Internal: PermissionsEvaluateManagedPolicyParams is an internal SDK API and is not part +// of the public surface. +type PermissionsEvaluateManagedPolicyParams struct { + // The `permissions` object from a managed settings layer, for example + // `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy + // applies. + Permissions any `json:"permissions,omitempty"` +} + +// The policy questions a host asks before granting elevated permissions. +// Experimental: PermissionsEvaluateManagedPolicyResult is part of an experimental API and +// may change or be removed. +type PermissionsEvaluateManagedPolicyResult struct { + // True when managed policy forbids bypass-permissions mode, so allow-all style flags must + // not take effect. + BypassPermissionsDisabled bool `json:"bypassPermissionsDisabled"` + // True when the managed layer supplies permission rules that the session must enforce. + PermissionRulesActive bool `json:"permissionRulesActive"` + // True when a managed policy exists but this build could not determine its meaning. Hosts + // fail closed on it rather than assuming permission was granted. + PolicyUndetermined bool `json:"policyUndetermined"` +} + // Indicates whether the operation succeeded. // Experimental: PermissionsFolderTrustAddTrustedResult is part of an experimental API and // may change or be removed. @@ -11862,6 +13851,31 @@ type PermissionURLsSetUnrestrictedModeParams struct { Enabled bool `json:"enabled"` } +// A complete JSON snapshot to write under the runtime's per-path file lock. +// Experimental: PersistenceWriteRawJSONLockedRequest is part of an experimental API and may +// change or be removed. +type PersistenceWriteRawJSONLockedRequest struct { + // The serialized JSON document to write. It replaces the file's contents entirely; nothing + // is merged. + DataJSON string `json:"dataJson"` + // Comment lines to emit above the document, for a format that tolerates them. Omit for + // strict JSON. + FileHeader *string `json:"fileHeader,omitempty"` + // Absolute path of the file to replace. Parent directories are created when missing. + Path string `json:"path"` +} + +// The outcome of a locked snapshot write. +// Experimental: PersistenceWriteRawJSONLockedResult is part of an experimental API and may +// change or be removed. +type PersistenceWriteRawJSONLockedResult struct { + // Why the write failed. Absent when `success` is true. A lock the runtime could not acquire + // in time reports here rather than raising. + Error *string `json:"error,omitempty"` + // Whether the file now holds the requested contents. + Success bool `json:"success"` +} + // Optional message to echo back to the caller. // Experimental: PingRequest is part of an experimental API and may change or be removed. type PingRequest struct { @@ -12484,6 +14498,114 @@ type ProviderModelConfig struct { WireModel *string `json:"wireModel,omitempty"` } +// An authoritative monthly usage reading for the observation's provider, account, and +// service. +// Experimental: ProviderMonthlyUsage is part of an experimental API and may change or be +// removed. +type ProviderMonthlyUsage struct { + // Nonnegative finite consumption reported by the service, preserving zero and fractions. + // Present only when state is available; never computed from tokens or balance differences. + ConsumedQuantity *float64 `json:"consumedQuantity,omitempty"` + // Start of the service-reported monthly billing cycle, in UTC RFC 3339. + CycleStart *string `json:"cycleStart,omitempty"` + // Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation + // of the latest inference charge. + QueriedAt *string `json:"queriedAt,omitempty"` + // End of the service-reported monthly billing cycle, in UTC RFC 3339. + ResetOn *string `json:"resetOn,omitempty"` + // Identity scope of the reading within its provider and service. + Scope ProviderMonthlyUsageScope `json:"scope"` + // Availability of monthly consumption. Missing or unavailable usage must never be + // interpreted as zero. + State ProviderMonthlyUsageState `json:"state"` + // Unit of consumedQuantity; independent of the parent observation's balance unit. + Unit ProviderQuotaUnit `json:"unit"` +} + +// Authoritative budget measurements and policy metadata, independent of provider. +// Experimental: ProviderQuotaBudgetMetadata is part of an experimental API and may change +// or be removed. +type ProviderQuotaBudgetMetadata struct { + // Exact measured consumption in the budget's unit. + Consumed float64 `json:"consumed"` + // Exact budget entitlement, retaining incumbent fractional-unit compatibility. + Entitlement float64 `json:"entitlement"` + // Usage beyond entitlement, in the budget's unit. + Overage float64 `json:"overage"` + // Whether additional usage is allowed when the budget is exhausted. + OverageAllowedWhenExhausted bool `json:"overageAllowedWhenExhausted"` + // Optional additional-usage budget cap. + OverageLimit *float64 `json:"overageLimit,omitempty"` + // Service-reported remaining percentage for authoritative budget presentation. + RemainingPercentage float64 `json:"remainingPercentage"` + // Reset instant in epoch milliseconds when this budget actually defines a window. + ResetAtEpochMs *float64 `json:"resetAtEpochMs,omitempty"` + // Whether the reset instant is an estimate. + ResetEstimated *bool `json:"resetEstimated,omitempty"` + // Whether this budget uses token-based billing. + TokenBasedBilling *bool `json:"tokenBasedBilling,omitempty"` + // Whether the budget has unlimited entitlement. + Unlimited bool `json:"unlimited"` + // Whether service policy allows continued usage after exhaustion. + UsageAllowedWhenExhausted bool `json:"usageAllowedWhenExhausted"` +} + +// An account quota reading. Absence of a quantity is unknown, never zero. +// Experimental: ProviderQuotaState is part of an experimental API and may change or be +// removed. +type ProviderQuotaState struct { + // Whether the service permits access, independently of balance. + AccessState ProviderQuotaAccessState `json:"accessState"` + // Service error code or client acquisition category, separate from the business-state + // reason. + AcquisitionError *string `json:"acquisitionError,omitempty"` + // Acquisition outcome. Unavailable/failed readings have no service verdict; access/capacity + // unavailable are compatibility placeholders only. + AcquisitionStatus *ProviderQuotaAcquisitionStatus `json:"acquisitionStatus,omitempty"` + // Independently reported signed 64-bit available quantity. Zero does not override the + // service access/capacity verdict; omission and null are preserved. + AvailableQuantity *int64 `json:"availableQuantity,omitempty"` + // Optional metadata for an authoritative budget. Advisory balances and admission-only + // observations do not populate this. + BudgetMetadata *ProviderQuotaBudgetMetadata `json:"budgetMetadata,omitempty"` + // Service capacity state; missing quantities do not imply exhaustion. + CapacityState ProviderQuotaCapacityState `json:"capacityState"` + // Key for the backwards-compatible snapshots projection, when the authoritative budget + // supports that contract. + CompatibilityKey *string `json:"compatibilityKey,omitempty"` + // Independently reported signed 64-bit entitlement. -1 is an unlimited sentinel, not a + // capacity-state rewrite; omission and null are preserved. + EntitledQuantity *int64 `json:"entitledQuantity,omitempty"` + // Explicit service admission flag, when reported. + HasQuota *bool `json:"hasQuota,omitempty"` + // HTTP status from acquisition, when available. + HTTPStatus *int64 `json:"httpStatus,omitempty"` + // Service-reported monthly consumption, independent of quota balances and per-call or + // session cost. Omitted when the service does not report monthly usage. + MonthlyUsage *ProviderMonthlyUsage `json:"monthlyUsage,omitempty"` + // Whether this is a GET account reading or a pre-response admission observation. + // Observations are never merged across kinds. + ObservationKind *ProviderQuotaObservationKind `json:"observationKind,omitempty"` + // When the runtime observed this reading, not a charge timestamp or guarantee that + // consumption has settled. + ObservedAt *string `json:"observedAt,omitempty"` + // Provider/account whose service reported this state. + Provider ModelProviderRef `json:"provider"` + // Whether quantities are authoritative budget measurements, advisory balances, or absent. + // Only authoritative budgets support percentage presentation. + QuantityKind *ProviderQuotaQuantityKind `json:"quantityKind,omitempty"` + // Service-owned quota identifier within this provider. + QuotaID string `json:"quotaId"` + // Service-reported explanation for the state. + Reason *string `json:"reason,omitempty"` + // Service name owning this reading. + Service *string `json:"service,omitempty"` + // Service-reported quota source. + Source *string `json:"source,omitempty"` + // Unit of entitledQuantity and availableQuantity. + Unit ProviderQuotaUnit `json:"unit"` +} + // Short-lived, rotating credential the caller must send on every request, in addition to // `apiKey` if one is present. Omitted when the endpoint does not require one. // Experimental: ProviderSessionToken is part of an experimental API and may change or be @@ -13318,6 +15440,23 @@ type QueueWithdrawMessageResult struct { Removed bool `json:"removed"` } +// Pending warnings returned and cleared by session.quota.takeWarnings. +// Experimental: QuotaTakeWarningsResult is part of an experimental API and may change or be +// removed. +type QuotaTakeWarningsResult []QuotaWarningProjection + +// A pending session quota warning, consumed once by takeWarnings. +// Experimental: QuotaWarningProjection is part of an experimental API and may change or be +// removed. +type QuotaWarningProjection struct { + // User-facing warning text. + Message string `json:"message"` + // Related account or upgrade link. + URL *string `json:"url,omitempty"` + // Existing warning category. + WarningType string `json:"warningType"` +} + // Event type to register consumer interest for, used by runtime gating logic. // Experimental: RegisterEventInterestParams is part of an experimental API and may change // or be removed. @@ -13581,6 +15720,100 @@ type RemoteSessionRepository struct { Owner string `json:"owner"` } +// One atomic edit of an allowed top-level repository setting. +// Experimental: RepoSettingsEditRequest is part of an experimental API and may change or be +// removed. +// Internal: RepoSettingsEditRequest is an internal SDK API and is not part of the public +// surface. +type RepoSettingsEditRequest struct { + // One canonical top-level repository setting that the allowlist permits. + Key string `json:"key"` + // Set a scalar, add or remove a string list item, or remove the setting. The handler + // rejects a missing or incompatible value. + // Internal: Operation is part of the SDK's internal API surface and is not intended for + // external use. + Operation SettingsEditOperation `json:"operation"` + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Shared or local repository settings file. + // Internal: Scope is part of the SDK's internal API surface and is not intended for + // external use. + Scope RepoSettingsEditScope `json:"scope"` + // Required boolean, string or number for set, required string for add-item and remove-item, + // and forbidden for remove. The runtime rejects all other JSON values. + Value any `json:"value,omitempty"` +} + +// Which repository settings file to read. +// Experimental: RepoSettingsReadRawRequest is part of an experimental API and may change or +// be removed. +// Internal: RepoSettingsReadRawRequest is an internal SDK API and is not part of the public +// surface. +type RepoSettingsReadRawRequest struct { + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + Scope string `json:"scope"` +} + +// Parsed repository settings without normalization or layering. +// Experimental: RepoSettingsReadRawResult is part of an experimental API and may change or +// be removed. +// Internal: RepoSettingsReadRawResult is an internal SDK API and is not part of the public +// surface. +type RepoSettingsReadRawResult struct { + // Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty + // when the file is missing, blank, or invalid. + Config any `json:"config"` + // True when the file exists but did not parse, so `config` is empty for that reason rather + // than because nothing is set. + Invalid bool `json:"invalid"` +} + +// The complete set of repository-overridable settings to store. +// Experimental: RepoSettingsWriteAllRequest is part of an experimental API and may change +// or be removed. +// Internal: RepoSettingsWriteAllRequest is an internal SDK API and is not part of the +// public surface. +type RepoSettingsWriteAllRequest struct { + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + Scope string `json:"scope"` + // Object of allowed settings to store. Missing allowlisted keys are removed. Other input + // keys are ignored, while unknown stored keys are preserved. + Settings any `json:"settings"` +} + +// Experimental: RepoSettingsWriteAllResult is part of an experimental API and may change or +// be removed. +type RepoSettingsWriteAllResult struct { +} + +// One key to write or remove in a repository settings file. +// Experimental: RepoSettingsWriteKeyRequest is part of an experimental API and may change +// or be removed. +// Internal: RepoSettingsWriteKeyRequest is an internal SDK API and is not part of the +// public surface. +type RepoSettingsWriteKeyRequest struct { + // True to remove the key instead of writing it. + Delete *bool `json:"delete,omitempty"` + // Canonical top-level key permitted by the repository settings allowlist. + Key string `json:"key"` + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + Scope string `json:"scope"` + // Value to validate and write. Required unless delete is true; a null value is validated, + // not treated as deletion. + Value any `json:"value,omitempty"` +} + +// Experimental: RepoSettingsWriteKeyResult is part of an experimental API and may change or +// be removed. +type RepoSettingsWriteKeyResult struct { +} + // Experimental: ResponseFormat is part of an experimental API and may change or be removed. type ResponseFormat struct { // JSON Schema and provider options for the turn's output. @@ -13594,6 +15827,30 @@ type ResponseFormat struct { type RuntimeShutdownResult struct { } +// The stored sandbox settings to resolve against the defaults. +// Experimental: SandboxApplyDefaultsRequest is part of an experimental API and may change +// or be removed. +type SandboxApplyDefaultsRequest struct { + // The sandbox settings as stored in the settings file. An empty object resolves to the + // defaults alone. + Stored any `json:"stored"` +} + +// True when the command stays available while enforcement is blocked. +// Experimental: SandboxCheckEnforcementCommandResult is part of an experimental API and may +// change or be removed. +type SandboxCheckEnforcementCommandResult bool + +// True when an OS-level sandbox can run on this host. +// Experimental: SandboxCheckPlatformSupportResult is part of an experimental API and may +// change or be removed. +type SandboxCheckPlatformSupportResult bool + +// True when the sandbox on this host can reach host loopback directly. +// Experimental: SandboxCheckWindowsHostLoopbackSupportResult is part of an experimental API +// and may change or be removed. +type SandboxCheckWindowsHostLoopbackSupportResult bool + // Resolved sandbox configuration. // Experimental: SandboxConfig is part of an experimental API and may change or be removed. type SandboxConfig struct { @@ -13783,6 +16040,29 @@ type SandboxCredentialsConfig struct { EnvVars map[string]SandboxMaskedEnvVar `json:"envVars"` } +// A possible secret-bearing environment variable and optional locally suggested HTTPS +// injection hosts. This is a draft for user review, not an active grant. +// Experimental: SandboxCredentialSuggestion is part of an experimental API and may change +// or be removed. +type SandboxCredentialSuggestion struct { + // Environment variable name. The secret value is never returned. + Name string `json:"name"` + // HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the + // user to supply injection hosts before adding a masking entry. These suggestions do not + // allow network access. + SuggestedInjectHosts []string `json:"suggestedInjectHosts"` +} + +// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, +// with no secret values. +// Experimental: SandboxCredentialSuggestionsResult is part of an experimental API and may +// change or be removed. +type SandboxCredentialSuggestionsResult struct { + // Candidates for user review. Empty when sandboxing is disabled or no unconfigured + // candidates are present. + Suggestions []SandboxCredentialSuggestion `json:"suggestions"` +} + // Request to disable sandboxing for the current session while resolving an active // sandbox-bypass permission prompt. // Experimental: SandboxDisableForSessionRequest is part of an experimental API and may @@ -13805,6 +16085,52 @@ type SandboxDisableForSessionResult struct { Success bool `json:"success"` } +// The documentation URL a host cites when it declines or downgrades a sandbox setting. +// Experimental: SandboxDocsURLResult is part of an experimental API and may change or be +// removed. +type SandboxDocsURLResult struct { + // Documentation URL describing the sandbox and the settings that control it. + URL string `json:"url"` +} + +// A sandbox config and the per-feature routing flag to resolve it for. +// Experimental: SandboxEffectiveForOptionalParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxEffectiveForOptionalParams is an internal SDK API and is not part of the +// public surface. +type SandboxEffectiveForOptionalParams struct { + // The routing flag naming the feature being launched, such as `sandboxMcpServers` or + // `sandboxLspServers`. + RoutingFlag string `json:"routingFlag"` + // The session's resolved `sandbox` slice. Omitted when the host has none, which yields a + // disabled sandbox rather than an error. + Sandbox any `json:"sandbox,omitempty"` +} + +// The sandbox a named feature actually launches under. +// Experimental: SandboxEffectiveForOptionalResult is part of an experimental API and may +// change or be removed. +// Internal: SandboxEffectiveForOptionalResult is an internal SDK API and is not part of the +// public surface. +type SandboxEffectiveForOptionalResult struct { + // The effective sandbox config for the requested feature, or a disabled sandbox when the + // feature is routed out of it. + SandboxJSON any `json:"sandboxJson"` +} + +// One slash command, as typed, to test against the enforcement-block allowlist. +// Experimental: SandboxEnforcementCommandAllowedParams is part of an experimental API and +// may change or be removed. +// Internal: SandboxEnforcementCommandAllowedParams is an internal SDK API and is not part +// of the public surface. +type SandboxEnforcementCommandAllowedParams struct { + // The command's arguments, in order. Pass an empty array for a bare command: several + // entries in the allowlist admit the bare form and refuse every argument. + Args []string `json:"args"` + // The command name as the user typed it, with or without its leading slash. + CommandName string `json:"commandName"` +} + // Managed sandbox enforcement state for a session. // Experimental: SandboxEnforcementStatus is part of an experimental API and may change or // be removed. @@ -13817,6 +16143,43 @@ type SandboxEnforcementStatus struct { Required bool `json:"required"` } +// A batch of file-picker candidates to check against a prepared policy. +// Experimental: SandboxFilterPickerCandidatesParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxFilterPickerCandidatesParams is an internal SDK API and is not part of +// the public surface. +type SandboxFilterPickerCandidatesParams struct { + // The candidates to check, in the order the answers are returned. + // Internal: Candidates is part of the SDK's internal API surface and is not intended for + // external use. + Candidates []SandboxPickerCandidate `json:"candidates"` + // The session's working directory, matching the one the policy was prepared from. + Cwd string `json:"cwd"` + // The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. + Sandbox any `json:"sandbox,omitempty"` +} + +// Per-candidate allow decisions, positionally aligned with the request. +// Experimental: SandboxFilterPickerCandidatesResult is part of an experimental API and may +// change or be removed. +// Internal: SandboxFilterPickerCandidatesResult is an internal SDK API and is not part of +// the public surface. +type SandboxFilterPickerCandidatesResult struct { + // One decision per candidate, in the same order. Always the same length as the request's + // `candidates`. + Allowed []bool `json:"allowed"` +} + +// The user-facing refusal, including the platform remedy and the documentation link. +// Experimental: SandboxGetUnsupportedMessageResult is part of an experimental API and may +// change or be removed. +type SandboxGetUnsupportedMessageResult string + +// The user-facing notice that a saved sandbox setting is inert for this session. +// Experimental: SandboxGetUnsupportedSettingDisabledNoticeResult is part of an experimental +// API and may change or be removed. +type SandboxGetUnsupportedSettingDisabledNoticeResult string + // Request to accept the sandbox path grant offered on an active sandbox escalation // permission prompt. // Experimental: SandboxGrantPathForRequestRequest is part of an experimental API and may @@ -13850,12 +16213,15 @@ type SandboxHostCapability struct { // tooling for Bubblewrap's private network namespace, such as slirp4netns), // `network_filtering` (host rules and the sandbox proxy; on Linux this needs the same // tooling as `network`; on Windows it needs Process Security Environment 1.1 host-loopback - // support, and a policy that uses it must also set `network.allowLocalNetwork`), - // `denied_paths` (native enforcement of `filesystem.deniedPaths`), `shell` (shell commands - // inside the sandbox), and `filesystem_enumeration` (enumerate-only filesystem grants; on - // Windows this needs Process Security Environment 1.1 filesystem enumeration support, and - // without it sandboxed PowerShell still runs but cannot resolve its current location; other - // platforms always report it). + // support or MXC's PSEC 1.0-only proxy-loopback compatibility capability, and a policy that + // uses it must also set `network.allowLocalNetwork`; compatibility applies only to an + // explicit identity-less runtime proxy, not general host-loopback access, and other policy + // restrictions still apply), `denied_paths` (native enforcement of + // `filesystem.deniedPaths`), `shell` (shell commands inside the sandbox), and + // `filesystem_enumeration` (enumerate-only filesystem grants; on Windows this needs Process + // Security Environment 1.1 filesystem enumeration support, and without it sandboxed + // PowerShell still runs but cannot resolve its current location; other platforms always + // report it). Name string `json:"name"` // Human-readable reason and remedy when the feature is unsupported, such as a package to // install or an OS update. Present only when `supported` is false. @@ -13871,17 +16237,20 @@ type SandboxHostCapability struct { // Bubblewrap's private network namespace, such as slirp4netns. `network_filtering` — host // rules and the sandbox proxy (`network.allowedHosts`, `network.blockedHosts`, // `network.proxy`); on Linux this needs the same tooling as `network`; on Windows it needs -// a version with Process Security Environment 1.1 host-loopback support, and a policy that -// uses it must also set `network.allowLocalNetwork`, because Windows reaches the local -// proxy only together with private-network access. `denied_paths` — native enforcement of -// `filesystem.deniedPaths`; on Windows this needs a version whose sandbox contract reports -// denied-path support. `shell` — shell commands inside the sandbox: bash on macOS and -// Linux, PowerShell on Windows. `filesystem_enumeration` — enumerate-only filesystem -// grants, which PowerShell's drive roots use on Windows; this needs a version with Process -// Security Environment 1.1 filesystem enumeration support. Without it, sandboxed PowerShell -// still runs, but `Get-Location` may report the drive root, `Set-Location` may fail, and -// relative paths may resolve against the drive root; the session also receives a -// `session.warning` with `warningType` `sandbox`. Other platforms always report it. +// Process Security Environment 1.1 host-loopback support or MXC's PSEC 1.0-only +// proxy-loopback compatibility capability, and a policy that uses it must also set +// `network.allowLocalNetwork`, because Windows reaches the local proxy only together with +// private-network access. Compatibility applies only to an explicit identity-less runtime +// proxy, not general host-loopback access, and other policy restrictions still apply. +// `denied_paths` — native enforcement of `filesystem.deniedPaths`; on Windows this needs a +// version whose sandbox contract reports denied-path support. `shell` — shell commands +// inside the sandbox: bash on macOS and Linux, PowerShell on Windows. +// `filesystem_enumeration` — enumerate-only filesystem grants, which PowerShell's drive +// roots use on Windows; this needs a version with Process Security Environment 1.1 +// filesystem enumeration support. Without it, sandboxed PowerShell still runs, but +// `Get-Location` may report the drive root, `Set-Location` may fail, and relative paths may +// resolve against the drive root; the session also receives a `session.warning` with +// `warningType` `sandbox`. Other platforms always report it. // Experimental: SandboxHostCapabilityName is part of an experimental API and may change or // be removed. type SandboxHostCapabilityName string @@ -13914,6 +16283,56 @@ type SandboxMaskedEnvVar struct { InjectHosts []string `json:"injectHosts"` } +// One file-picker suggestion offered up for the sandbox filesystem check. +// Experimental: SandboxPickerCandidate is part of an experimental API and may change or be +// removed. +// Internal: SandboxPickerCandidate is an internal SDK API and is not part of the public +// surface. +type SandboxPickerCandidate struct { + // Whether the suggestion is a directory. A directory the policy does not itself allow may + // still be needed as a waypoint to an allowed subtree. + IsDirectory bool `json:"isDirectory"` + // Absolute path the suggestion would attach. + Path string `json:"path"` +} + +// The working directory and sandbox settings to build a file-picker policy from. +// Experimental: SandboxPreparePickerPolicyParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxPreparePickerPolicyParams is an internal SDK API and is not part of the +// public surface. +type SandboxPreparePickerPolicyParams struct { + // The session's working directory. Git discovery and grant canonicalization are resolved + // against it. + Cwd string `json:"cwd"` + // The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every + // candidate is kept. + Sandbox any `json:"sandbox,omitempty"` +} + +// The prepared file-picker policy, or none when the sandbox is disabled. +// Experimental: SandboxPreparePickerPolicyResult is part of an experimental API and may +// change or be removed. +// Internal: SandboxPreparePickerPolicyResult is an internal SDK API and is not part of the +// public surface. +type SandboxPreparePickerPolicyResult struct { + // The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the + // sandbox is disabled or absent, in which case filtering keeps every candidate. + SandboxJSON any `json:"sandboxJson,omitempty"` +} + +// True when this process can offer installing the sandbox credential-proxy certificate +// authority into OS trust. +// Experimental: SandboxProxyCaCheckInstallationSupportResult is part of an experimental API +// and may change or be removed. +type SandboxProxyCaCheckInstallationSupportResult bool + +// True when the sandbox configuration uses the credential proxy and can need +// certificate-authority setup. +// Experimental: SandboxProxyCaCheckRelevanceResult is part of an experimental API and may +// change or be removed. +type SandboxProxyCaCheckRelevanceResult bool + // Result of creating the persistent certificate authority of the sandbox credential proxy. // Experimental: SandboxProxyCaCreateResult is part of an experimental API and may change or // be removed. @@ -13949,6 +16368,108 @@ type SandboxProxyCaStatus struct { State SandboxProxyCaState `json:"state"` } +// Experimental: SandboxProxySecretDeleteResult is part of an experimental API and may +// change or be removed. +type SandboxProxySecretDeleteResult struct { +} + +// The stored sandbox proxy password, if one is present. +// Experimental: SandboxProxySecretGetResult is part of an experimental API and may change +// or be removed. +type SandboxProxySecretGetResult struct { + // The stored password. Absent when no entry exists in either the keychain or the on-disk + // fallback store. + Value *string `json:"value,omitempty"` +} + +// Where this runtime keeps the sandbox proxy password. +// Experimental: SandboxProxySecretLocation is part of an experimental API and may change or +// be removed. +type SandboxProxySecretLocation struct { + // Absolute path of the credential store holding the sandbox proxy password. The proxy + // password belongs to no MCP server, so it is kept in its own directory rather than in the + // MCP secret store. + ConfigDir string `json:"configDir"` + // Identifier of the proxy password entry within that store. Derived from the configuration + // directory, so two Copilot homes on one machine never share an entry. Use it to recognize + // a `${secret:…}` reference in stored settings as this runtime's own proxy password. + SecretID string `json:"secretId"` +} + +// The sandbox proxy password to store. +// Experimental: SandboxProxySecretSaveRequest is part of an experimental API and may change +// or be removed. +type SandboxProxySecretSaveRequest struct { + // The password to store for the sandbox proxy. + Value string `json:"value"` +} + +// Where the sandbox proxy password was stored. +// Experimental: SandboxProxySecretSaveResult is part of an experimental API and may change +// or be removed. +type SandboxProxySecretSaveResult struct { + // Whether the OS keychain accepted the value. False means it was written to the on-disk + // fallback store instead, which is still readable by `sandbox.proxySecret.get`. + StoredInKeychain bool `json:"storedInKeychain"` +} + +// The user's sandbox settings and the managed sandbox floor to raise them to. +// Experimental: SandboxResolveFlooredConfigParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxResolveFlooredConfigParams is an internal SDK API and is not part of the +// public surface. +type SandboxResolveFlooredConfigParams struct { + // The effective managed `sandbox` slice acting as a floor. Omitted when no administrator + // policy applies, in which case the user's own settings stand unchanged. + ManagedSandbox any `json:"managedSandbox,omitempty"` + // The user's own `sandbox` settings slice. Omitted when the user has configured none, which + // still yields the managed floor rather than a disabled sandbox. + UserSandbox any `json:"userSandbox,omitempty"` +} + +// The user's sandbox settings raised to the managed floor. +// Experimental: SandboxResolveFlooredConfigResult is part of an experimental API and may +// change or be removed. +type SandboxResolveFlooredConfigResult struct { + // The floored sandbox config, normalized through the declared sandbox shape so only + // declared fields in a fixed order are present. + SandboxJSON any `json:"sandboxJson"` +} + +// The effective sandbox settings, with every unset value resolved to its default. +// Experimental: SandboxSettingsApplyDefaultsResult is part of an experimental API and may +// change or be removed. +type SandboxSettingsApplyDefaultsResult map[string]any + +// The managed sandbox policy in force, which selects which remedy the notice offers. +// Experimental: SandboxUnsupportedStartupNoticeParams is part of an experimental API and +// may change or be removed. +// Internal: SandboxUnsupportedStartupNoticeParams is an internal SDK API and is not part of +// the public surface. +type SandboxUnsupportedStartupNoticeParams struct { + // True when the sandbox stayed on only because the managed policy could not be determined. + // Distinguishes a policy that positively enforces the sandbox from one that merely failed + // to resolve, which is the difference between telling the user to contact an administrator + // and telling them to wait. Defaults to false. + EnabledByUndeterminedPolicy *bool `json:"enabledByUndeterminedPolicy,omitempty"` + // The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as + // enforced only when this both enables it and sets `failIfUnavailable`, because a managed + // sandbox that tolerates being unavailable still leaves the user able to turn it off. + ManagedSandbox any `json:"managedSandbox,omitempty"` +} + +// The startup warning, absent when the machine can run a sandbox. +// Experimental: SandboxUnsupportedStartupNoticeResult is part of an experimental API and +// may change or be removed. +// Internal: SandboxUnsupportedStartupNoticeResult is an internal SDK API and is not part of +// the public surface. +type SandboxUnsupportedStartupNoticeResult struct { + // The user-facing warning, carrying the platform remedy and the recovery the policy in + // force actually allows. Absent when this machine supports a sandbox, so a host can call + // unconditionally and print only what it gets. + Notice *string `json:"notice,omitempty"` +} + // Register an absolute-time scheduled prompt. // Experimental: ScheduleAddAtRequest is part of an experimental API and may change or be // removed. @@ -14475,6 +16996,16 @@ type SessionCompletionItem struct { RangeStart *int64 `json:"rangeStart,omitempty"` } +// The IDE a host is connected to, as reported to the session. +// Experimental: SessionConnectedIdeInfo is part of an experimental API and may change or be +// removed. +type SessionConnectedIdeInfo struct { + // Display name of the connected IDE, for example `VS Code`. + IdeName string `json:"ideName"` + // Absolute path of the workspace folder the IDE has open. + WorkspaceFolder string `json:"workspaceFolder"` +} + // Pre-resolved working-directory context for session startup. // Experimental: SessionContext is part of an experimental API and may change or be removed. type SessionContext struct { @@ -14495,7 +17026,8 @@ type SessionContext struct { // Experimental: SessionContextAttribution is part of an experimental API and may change or // be removed. type SessionContextAttribution struct { - // Output reserve plus the tokens past the buffer-exhaustion blocking threshold. Mirrors + // Output reservation overlapping the displayed prompt allowance plus the tokens past the + // effective input budget's buffer-exhaustion blocking threshold. Mirrors // `SessionContextInfo.bufferTokens`. BufferTokens int64 `json:"bufferTokens"` // The six normalized `/context` header buckets, computed from the same tokenization as @@ -14511,9 +17043,9 @@ type SessionContextAttribution struct { // Flat list of per-source attribution entries. Group by `kind` and render unrecognized // kinds generically. Nesting and rollups are expressed via `parentId`. Entries []SessionContextAttributionEntriesItem `json:"entries"` - // Prompt limit plus the model's output reserve: the full context window - // `categories.freeSpace` and `categories.buffer` are measured against. Mirrors - // `SessionContextInfo.limit`. + // Advertised prompt allowance for the selected context tier: the denominator for + // context-usage displays and capacity for `categories.freeSpace` and `categories.buffer`. + // Mirrors `SessionContextInfo.limit`. Limit int64 `json:"limit"` // The concrete model id the entire breakdown was tokenized against (feeds the per-model // token multiplier). Under `Auto` (Free/Student) this is the resolved model, not the @@ -14524,8 +17056,8 @@ type SessionContextAttribution struct { // `autoResolved` (the model Auto resolved to), `selected` (the user's explicitly selected // model), `default` (a fallback before any model is known). ModelSource string `json:"modelSource"` - // Maximum prompt tokens the resolved model accepts — the denominator for a `##k/###k` - // context-usage display. Mirrors `SessionContextInfo.promptTokenLimit`. + // Effective input budget after reserving requested output against the combined context + // ceiling. Mirrors `SessionContextInfo.promptTokenLimit`. PromptTokenLimit int64 `json:"promptTokenLimit"` // Total token count of the current context window the entries are measured against (system // message + conversation messages + tool definitions — the same total reported by @@ -14538,7 +17070,7 @@ type SessionContextAttribution struct { // describe window capacity rather than occupied context, so the values do not sum to // `totalTokens`. type SessionContextAttributionCategories struct { - // Output reserve plus post-blocking-threshold buffer. + // Overlapping output reservation plus post-blocking-threshold buffer. Buffer int64 `json:"buffer"` // Custom-instructions tokens (0 when none are configured). CustomInstructions int64 `json:"customInstructions"` @@ -14588,22 +17120,32 @@ type SessionContextAttributionEntriesItem struct { // Experimental: SessionContextInfo is part of an experimental API and may change or be // removed. type SessionContextInfo struct { - // Output reserve plus tokens after the buffer-exhaustion blocking threshold (default 95%) + // Output reservation overlapping the displayed prompt allowance plus tokens after the + // effective input budget's buffer-exhaustion blocking threshold (default 95%). BufferTokens int64 `json:"bufferTokens"` // Token count at which background compaction starts (configurable percentage of // promptTokenLimit) CompactionThreshold int64 `json:"compactionThreshold"` // Tokens consumed by user/assistant/tool messages ConversationTokens int64 `json:"conversationTokens"` - // Prompt token limit plus the model's full output token limit. + // Provider-owned model display label, or the Auto routing label. Presentation only; + // modelName remains the tokenization identity. + DisplayModelName *string `json:"displayModelName,omitempty"` + // Advertised prompt allowance for the selected context tier, without adding output tokens. + // The denominator for context-usage displays. Limit int64 `json:"limit"` // Tokens consumed by MCP tool definitions (subset of toolDefinitionsTokens, excludes // deferred tools) 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) + // Effective input budget: the selected tier's prompt allowance bounded by the combined + // context ceiling minus the requested output allowance. Uses DEFAULT_TOKEN_LIMIT when + // limits are unspecified. PromptTokenLimit int64 `json:"promptTokenLimit"` + // Provider whose catalog supplies this context window. Omitted when provider identity is + // unavailable. + Provider *ModelProviderRef `json:"provider,omitempty"` // Tokens consumed by the system prompt SystemTokens int64 `json:"systemTokens"` // Tokens consumed by tool definitions sent to the model (excludes deferred tools) @@ -15356,12 +17898,21 @@ type SessionManagedPermissions struct { Ask []string `json:"ask,omitzero"` // Permission rules that block matching operations. Deny has highest precedence. Deny []string `json:"deny,omitzero"` + // When true, prevents Assisted Permissions from being activated. An actively Assisted + // session falls back to Manual Approval while the policy is in force. Omit the key or set + // it to false to impose no restriction. + DisableAssistedPermissionsMode *bool `json:"disableAssistedPermissionsMode,omitempty"` // When set to `disable`, prevents bypass/allow-all permission modes. Advisory auto-approval // remains available because normal prompt paths stay active. Any other value is accepted // rather than failing the session, but is enforced as `disable`: the key is only present to // restrict something, so a mode this runtime cannot interpret fails closed to the most // restrictive one it knows. Omit the key entirely to impose no restriction. DisableBypassPermissionsMode *string `json:"disableBypassPermissionsMode,omitempty"` + // Closed-world host boundary expressed as `Domain(hostname)`, `Domain(IP)`, or + // `Domain(*.example.com)` rules. Schemes, ports, paths, queries, and fragments are rejected + // because every network request must be enforceable at host-level egress. Multiple managed + // sources intersect their lists; an empty list denies all hosts. + LimitTo []string `json:"limitTo,omitzero"` } // Managed settings an SDK host may inject at session startup. Only permissions are accepted @@ -15465,6 +18016,20 @@ type SessionMCPReloadResult struct { type SessionMCPRestartServerResult struct { } +// Records which IDE the host is connected to, or clears it. +// Experimental: SessionMCPSetConnectedIdeInfoParams is part of an experimental API and may +// change or be removed. +type SessionMCPSetConnectedIdeInfoParams struct { + // The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports + // that it is disconnected. + Ide *SessionConnectedIdeInfo `json:"ide,omitempty"` +} + +// Experimental: SessionMCPSetConnectedIdeInfoResult is part of an experimental API and may +// change or be removed. +type SessionMCPSetConnectedIdeInfoResult struct { +} + // Experimental: SessionMCPStartServerResult is part of an experimental API and may change // or be removed. type SessionMCPStartServerResult struct { @@ -15530,10 +18095,30 @@ type SessionMetadataSnapshot struct { WorkspacePath *string `json:"workspacePath"` } +// Experimental: SessionModelClearStartupSeedRequest is part of an experimental API and may +// change or be removed. +// Internal: SessionModelClearStartupSeedRequest is an internal SDK API and is not part of +// the public surface. +type SessionModelClearStartupSeedRequest struct { + ExpectedModel string `json:"expectedModel"` + // Provider captured with the startup seed; omission matches only an unqualified seed. + ExpectedProviderID *string `json:"expectedProviderId,omitempty"` +} + +// Experimental: SessionModelClearStartupSeedResult is part of an experimental API and may +// change or be removed. +// Internal: SessionModelClearStartupSeedResult is an internal SDK API and is not part of +// the public surface. +type SessionModelClearStartupSeedResult struct { + Cleared bool `json:"cleared"` +} + // The list of models available to this session. // Experimental: SessionModelList is part of an experimental API and may change or be // removed. type SessionModelList struct { + // Ordered Auto routing preferences discovered for this session's account. + Auto *AutoTierMetadata `json:"auto,omitempty"` // Available models, ordered with the most preferred default first. Includes both Copilot // (CAPI) models and any registry BYOK models; a BYOK model appears under its // provider-qualified selection id (`provider/id`). @@ -15595,6 +18180,12 @@ type SessionOpenOptions struct { AdditionalDirectories []string `json:"additionalDirectories,omitzero"` // Runtime context discriminator for agent filtering. AgentContext *string `json:"agentContext,omitempty"` + // Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + // Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK + // paths resolve once when supplied against the request's effective workingDirectory; + // retained roots do not move on cwd changes. Null and omission are equivalent; [] clears + // only the explicit SDK contribution. + AgentDirectories []string `json:"agentDirectories,omitzero"` // Whether to include instructions from every MCP server in the system prompt instead of // only allowlisted servers. AllowAllMCPServerInstructions *bool `json:"allowAllMcpServerInstructions,omitempty"` @@ -15604,6 +18195,12 @@ type SessionOpenOptions struct { AuthClientIDMetadataURL *string `json:"authClientIdMetadataUrl,omitempty"` // Initial authentication info for the session. AuthInfo AuthInfo `json:"authInfo,omitempty"` + // Whether a CLI host explicitly requested the initial Auto preference. False preserves a + // settings-derived preference without validating availability during creation; execution + // still validates it. Defaults to true and is ignored for non-CLI callers. + // Internal: AutoTierIsExplicit is part of the SDK's internal API surface and is not + // intended for external use. + AutoTierIsExplicit *bool `json:"autoTierIsExplicit,omitempty"` // Allowlist of available tool names. AvailableTools []string `json:"availableTools,omitzero"` // Options scoped to the built-in CAPI (Copilot API) provider. @@ -15666,11 +18263,15 @@ type SessionOpenOptions struct { EnableOnDemandInstructionDiscovery *bool `json:"enableOnDemandInstructionDiscovery,omitempty"` // Whether shell-script safety heuristics are enabled. EnableScriptSafety *bool `json:"enableScriptSafety,omitempty"` - // Whether skill loading is enabled. When omitted, an SDK skill provider enables skills by - // default. + // Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill + // provider enable skills independently of enableConfigDiscovery. EnableSkills *bool `json:"enableSkills,omitempty"` // Whether model responses stream as delta events. EnableStreaming *bool `json:"enableStreaming,omitempty"` + // Opt in to enforcing non-overridable managed model controls on session model, Auto-tier, + // reasoning-effort, and context-tier changes. Managed defaults still apply when omitted; + // this option only turns conflicting changes into errors. + EnforceManagedModelDefaults *bool `json:"enforceManagedModelDefaults,omitempty"` // How MCP server environment values are interpreted. EnvValueMode *SessionOpenOptionsEnvValueMode `json:"envValueMode,omitempty"` // Override directory for session event logs. @@ -15702,6 +18303,13 @@ type SessionOpenOptions struct { // Internal: HasSkillProvider is part of the SDK's internal API surface and is not intended // for external use. HasSkillProvider *bool `json:"hasSkillProvider,omitempty"` + // Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + // grants. Available without enableConfigDiscovery or enableFileHooks, which controls + // repository-origin hooks only; hook/managed disables still apply. Relative SDK paths + // resolve once when supplied against the request's effective workingDirectory; retained + // roots do not move on cwd changes. Null and omission are equivalent; [] clears only the + // explicit SDK contribution. + HookDirectories []string `json:"hookDirectories,omitzero"` // Skill scan directories and descendants excluded from discovery. Supports `~`-relative // paths. IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` @@ -15715,6 +18323,12 @@ type SessionOpenOptions struct { IncludedBuiltinSkills []string `json:"includedBuiltinSkills,omitzero"` // Installed plugins visible to the session. InstalledPlugins []InstalledPlugin `json:"installedPlugins,omitzero"` + // Explicit discovery-only instruction roots using existing SDK instruction formats, not + // filesystem grants. Available without enableConfigDiscovery, subject to + // instruction/managed disables. Relative SDK paths resolve once when supplied against the + // request's effective workingDirectory; retained roots do not move on cwd changes. Null and + // omission are equivalent; [] clears only the explicit SDK contribution. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Stable integration identifier for analytics. IntegrationID *string `json:"integrationId,omitempty"` // Whether experimental behavior is enabled. @@ -15792,7 +18406,11 @@ type SessionOpenOptions struct { ShellInitProfile *string `json:"shellInitProfile,omitempty"` // PowerShell process flags applied to built-in and user-requested shell commands. ShellProcessFlags []string `json:"shellProcessFlags,omitzero"` - // Additional directories to search for skills. + // Explicit discovery-only skill roots, not filesystem grants. Available without + // enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once + // when supplied against the request's effective workingDirectory; retained roots do not + // move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK + // contribution. SkillDirectories []string `json:"skillDirectories,omitzero"` // Whether to skip custom instruction sources. SkipCustomInstructions *bool `json:"skipCustomInstructions,omitempty"` @@ -16112,6 +18730,23 @@ type SessionPluginsReloadRequest struct { type SessionPluginsReloadResult struct { } +// Experimental: SessionPluginsRetryManagedRequest is part of an experimental API and may +// change or be removed. +type SessionPluginsRetryManagedRequest struct { + // "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed + // settings require. + Plugins []string `json:"plugins,omitzero"` +} + +// Per-plugin outcomes of retrying the plugins required by the session's managed settings. +// Experimental: SessionPluginsRetryManagedResult is part of an experimental API and may +// change or be removed. +type SessionPluginsRetryManagedResult struct { + // One entry per requested plugin, in request order. When no plugins were requested, one + // entry per plugin the managed settings require. + Plugins []ManagedPluginRetryEntry `json:"plugins"` +} + // Experimental: SessionPluginsUninstallResult is part of an experimental API and may change // or be removed. type SessionPluginsUninstallResult struct { @@ -16162,6 +18797,147 @@ type SessionQueueProcessResult struct { type SessionQueueSetDrainPausedResult struct { } +// Existing delegation guidance for an account without delegation access. +// Experimental: SessionQuotaDelegateWarning is part of an experimental API and may change +// or be removed. +type SessionQuotaDelegateWarning struct { + // User-facing guidance. + Text string `json:"text"` + // Link to upgrade the account. + URL string `json:"url"` +} + +// The incumbent session-owned quota and account projection. +// Experimental: SessionQuotaGetResult is part of an experimental API and may change or be +// removed. +type SessionQuotaGetResult struct { + // Whether the account can sign up for Copilot Free. + CanSignupForCopilotFree bool `json:"canSignupForCopilotFree"` + // Whether the account can delegate tasks to GitHub. + DelegateAvailable bool `json:"delegateAvailable"` + // Existing delegation warning for a free account. + DelegateWarning *SessionQuotaDelegateWarning `json:"delegateWarning,omitempty"` + // Whether dynamic workflows are enabled for the active account. + DynamicWorkflowsEnabled bool `json:"dynamicWorkflowsEnabled"` + // Whether dynamic workflows are visible under the session's feature flags. + DynamicWorkflowsUIVisible bool `json:"dynamicWorkflowsUiVisible"` + // Whether the account uses the free limited Copilot plan. + IsFreeUser bool `json:"isFreeUser"` + // Whether the account uses token-based billing. + IsTbbUser bool `json:"isTbbUser"` + // Whether model cost columns should be shown. + ModelCostColumnVisible bool `json:"modelCostColumnVisible"` + // Resolved Copilot plan tier. + PlanTier SessionQuotaPlanTier `json:"planTier"` + // Whether premium-request costs are billable. + PremiumRequestsBillable bool `json:"premiumRequestsBillable"` + // Provider-owned account quota state, including snapshots without numeric balances. + ProviderQuotas []ProviderQuotaState `json:"providerQuotas,omitzero"` + // Known quota snapshots, keyed by the provider's quota type. + Snapshots map[string]SessionQuotaSnapshot `json:"snapshots"` + // Upgrade link for a free account. + UpgradeURL *string `json:"upgradeUrl,omitempty"` +} + +// The incumbent session-owned quota and account projection. +// Experimental: SessionQuotaProjection is part of an experimental API and may change or be +// removed. +type SessionQuotaProjection struct { + // Whether the account can sign up for Copilot Free. + CanSignupForCopilotFree bool `json:"canSignupForCopilotFree"` + // Whether the account can delegate tasks to GitHub. + DelegateAvailable bool `json:"delegateAvailable"` + // Existing delegation warning for a free account. + DelegateWarning *SessionQuotaDelegateWarning `json:"delegateWarning,omitempty"` + // Whether dynamic workflows are enabled for the active account. + DynamicWorkflowsEnabled bool `json:"dynamicWorkflowsEnabled"` + // Whether dynamic workflows are visible under the session's feature flags. + DynamicWorkflowsUIVisible bool `json:"dynamicWorkflowsUiVisible"` + // Whether the account uses the free limited Copilot plan. + IsFreeUser bool `json:"isFreeUser"` + // Whether the account uses token-based billing. + IsTbbUser bool `json:"isTbbUser"` + // Whether model cost columns should be shown. + ModelCostColumnVisible bool `json:"modelCostColumnVisible"` + // Resolved Copilot plan tier. + PlanTier SessionQuotaPlanTier `json:"planTier"` + // Whether premium-request costs are billable. + PremiumRequestsBillable bool `json:"premiumRequestsBillable"` + // Provider-owned account quota state, including snapshots without numeric balances. + ProviderQuotas []ProviderQuotaState `json:"providerQuotas,omitzero"` + // Known quota snapshots, keyed by the provider's quota type. + Snapshots map[string]SessionQuotaSnapshot `json:"snapshots"` + // Upgrade link for a free account. + UpgradeURL *string `json:"upgradeUrl,omitempty"` +} + +// The incumbent session-owned quota and account projection. +// Experimental: SessionQuotaRefreshResult is part of an experimental API and may change or +// be removed. +type SessionQuotaRefreshResult struct { + // Whether the account can sign up for Copilot Free. + CanSignupForCopilotFree bool `json:"canSignupForCopilotFree"` + // Whether the account can delegate tasks to GitHub. + DelegateAvailable bool `json:"delegateAvailable"` + // Existing delegation warning for a free account. + DelegateWarning *SessionQuotaDelegateWarning `json:"delegateWarning,omitempty"` + // Whether dynamic workflows are enabled for the active account. + DynamicWorkflowsEnabled bool `json:"dynamicWorkflowsEnabled"` + // Whether dynamic workflows are visible under the session's feature flags. + DynamicWorkflowsUIVisible bool `json:"dynamicWorkflowsUiVisible"` + // Whether the account uses the free limited Copilot plan. + IsFreeUser bool `json:"isFreeUser"` + // Whether the account uses token-based billing. + IsTbbUser bool `json:"isTbbUser"` + // Whether model cost columns should be shown. + ModelCostColumnVisible bool `json:"modelCostColumnVisible"` + // Resolved Copilot plan tier. + PlanTier SessionQuotaPlanTier `json:"planTier"` + // Whether premium-request costs are billable. + PremiumRequestsBillable bool `json:"premiumRequestsBillable"` + // Provider-owned account quota state, including snapshots without numeric balances. + ProviderQuotas []ProviderQuotaState `json:"providerQuotas,omitzero"` + // Known quota snapshots, keyed by the provider's quota type. + Snapshots map[string]SessionQuotaSnapshot `json:"snapshots"` + // Upgrade link for a free account. + UpgradeURL *string `json:"upgradeUrl,omitempty"` +} + +// Session quota snapshot, preserving the incumbent numeric units and reset metadata. +// Experimental: SessionQuotaSnapshot is part of an experimental API and may change or be +// removed. +type SessionQuotaSnapshot struct { + // Entitled quantity in this quota's units. + EntitlementRequests float64 `json:"entitlementRequests"` + // Whether the provider reports available quota. + HasQuota *bool `json:"hasQuota,omitempty"` + // Whether the entitlement is unlimited. + IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` + // Additional usage in this quota's units. + Overage float64 `json:"overage"` + // Whether additional usage is allowed after quota exhaustion. + OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` + // Additional-usage budget cap, when provided. + OverageEntitlement *float64 `json:"overageEntitlement,omitempty"` + // Percentage of the entitlement remaining. + RemainingPercentage float64 `json:"remainingPercentage"` + // Quota reset time in milliseconds since the Unix epoch, when known. + ResetDateEpochMs *float64 `json:"resetDateEpochMs,omitempty"` + // Whether the reset time is estimated. + ResetDateEstimated *bool `json:"resetDateEstimated,omitempty"` + // Whether this quota uses token-based billing. + TokenBasedBilling *bool `json:"tokenBasedBilling,omitempty"` + // Whether usage is allowed after quota exhaustion. + UsageAllowedWithExhaustedQuota bool `json:"usageAllowedWithExhaustedQuota"` + // Consumed quantity in this quota's units. + UsedRequests float64 `json:"usedRequests"` +} + +// Pending warnings returned and cleared by session.quota.takeWarnings. +// Experimental: SessionQuotaTakeWarningsResult is part of an experimental API and may +// change or be removed. +type SessionQuotaTakeWarningsResult []QuotaWarningProjection + // Experimental: SessionRemoteDisableResult is part of an experimental API and may change or // be removed. type SessionRemoteDisableResult struct { @@ -16293,6 +19069,35 @@ type SessionsCloseResult struct { type SessionsConfigureSessionExtensionsResult struct { } +// Identity, state location and starting context for a workspace record. +// Experimental: SessionsCreateWorkspaceRequest is part of an experimental API and may +// change or be removed. +type SessionsCreateWorkspaceRequest struct { + // Starting working-directory context. The record keeps `cwd`, `gitRoot`, `repository`, + // `hostType`, `branch`, and `clientName`. Other fields, including `repositoryHost`, + // `headCommit`, and `baseCommit`, are ignored. `hostType` must be `github` or `ado`. + Context *SessionWorkingDirectoryContextWithClient `json:"context,omitempty"` + // `windows` (any letter case) selects Windows path rules. Any other value selects POSIX + // path rules. + Convention string `json:"convention"` + // User-supplied display name for the workspace + Name *string `json:"name,omitempty"` + // Session ID the workspace record belongs to + SessionID string `json:"sessionId"` + // Directory the session's state is written under when no session filesystem provider is + // configured. Ignored when a provider is configured; the provider's session state path is + // used instead. + SessionStatePath string `json:"sessionStatePath"` +} + +// The workspace record that was written. +// Experimental: SessionsCreateWorkspaceResult is part of an experimental API and may change +// or be removed. +type SessionsCreateWorkspaceResult struct { + // The created workspace record, as JSON + WorkspaceJSON string `json:"workspaceJson"` +} + // Session ID to delete from disk. // Experimental: SessionsDeleteRequest is part of an experimental API and may change or be // removed. @@ -16729,6 +19534,25 @@ type SessionsLoadDeferredRepoHooksRequest struct { SessionID string `json:"sessionId"` } +// Where the session's state lives, as a root directory and the session ID under it. +// Experimental: SessionsLoadWorkspaceRequest is part of an experimental API and may change +// or be removed. +type SessionsLoadWorkspaceRequest struct { + // Session ID naming the state directory under the sessions home. Rejected when it is + // absolute or contains a parent component, so it cannot escape the sessions home. + SessionID string `json:"sessionId"` + // Root directory every session's state directory sits under + SessionsHome string `json:"sessionsHome"` +} + +// The workspace record on disk, omitted when the session has none. +// Experimental: SessionsLoadWorkspaceResult is part of an experimental API and may change +// or be removed. +type SessionsLoadWorkspaceResult struct { + // The workspace record, as JSON. Omitted when the record does not exist. + WorkspaceJSON *string `json:"workspaceJson,omitempty"` +} + // `sessions.open` handoff progress update with step, status, and optional message. // Experimental: SessionsOpenProgress is part of an experimental API and may change or be // removed. @@ -16884,6 +19708,30 @@ type SessionsTransferRemoteControlRequest struct { ToSessionID string `json:"toSessionId"` } +// Where the session's state lives, plus workspace-schema fields to merge into its workspace +// record. Stored keys outside the schema are not preserved, and a stored `fork_count` is +// never replaced. +// Experimental: SessionsUpdateWorkspaceFieldsRequest is part of an experimental API and may +// change or be removed. +type SessionsUpdateWorkspaceFieldsRequest struct { + // Workspace-schema fields to merge into the record, as a JSON object. Fields the object + // omits keep their stored values, except stored keys outside the schema are not preserved + // and a stored `fork_count` is never replaced. + FieldsJSON string `json:"fieldsJson"` + // Session ID naming the state directory under the sessions home. Rejected when it is + // absolute or contains a parent component, so it cannot escape the sessions home. + SessionID string `json:"sessionId"` + // Root directory every session's state directory sits under + SessionsHome string `json:"sessionsHome"` +} + +// The merge completed. The record carries the supplied workspace-schema fields, but a +// stored `fork_count` stays. +// Experimental: SessionsUpdateWorkspaceFieldsResult is part of an experimental API and may +// change or be removed. +type SessionsUpdateWorkspaceFieldsResult struct { +} + // Experimental: SessionSuspendResult is part of an experimental API and may change or be // removed. type SessionSuspendResult struct { @@ -16912,6 +19760,12 @@ type SessionUpdateOptionsParams struct { AdditionalContentExclusionPolicies []OptionsUpdateAdditionalContentExclusionPolicy `json:"additionalContentExclusionPolicies,omitzero"` // Runtime context discriminator (e.g., `cli`, `actions`). AgentContext *string `json:"agentContext,omitempty"` + // Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + // Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK + // paths resolve once when supplied against the request's effective workingDirectory; + // retained roots do not move on cwd changes. Null and omission are equivalent; [] clears + // only the explicit SDK contribution. + AgentDirectories []string `json:"agentDirectories,omitzero"` // Whether to include instructions from every MCP server in the system prompt instead of // only allowlisted servers. AllowAllMCPServerInstructions *bool `json:"allowAllMcpServerInstructions,omitempty"` @@ -16939,8 +19793,9 @@ type SessionUpdateOptionsParams struct { DisabledInstructionSources []string `json:"disabledInstructionSources,omitzero"` // Skill IDs that should be excluded from this session. DisabledSkills []string `json:"disabledSkills,omitzero"` - // Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK - // callback hook mechanism. + // Whether to enable repository-origin file hooks from `.github/hooks/` and trusted + // repository-configured roots. Does not control explicit hookDirectories or SDK callback + // hooks. EnableFileHooks *bool `json:"enableFileHooks,omitempty"` // Whether to enable host git operations (context resolution, child repo scanning, git info // in system prompt). @@ -16955,9 +19810,10 @@ type SessionUpdateOptionsParams struct { EnableScriptSafety *bool `json:"enableScriptSafety,omitempty"` // Whether to enable cross-session store writes and reads. EnableSessionStore *bool `json:"enableSessionStore,omitempty"` - // Whether skill loading is enabled. Explicit false disables every source, including a bound - // SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, - // creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + // Whether skill loading is enabled. Explicit false disables every source, including + // explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded + // skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless + // explicit SDK skill roots or an SDK skill provider are supplied. EnableSkills *bool `json:"enableSkills,omitempty"` // Whether to stream model responses. EnableStreaming *bool `json:"enableStreaming,omitempty"` @@ -16977,6 +19833,13 @@ type SessionUpdateOptionsParams struct { ExcludedTools []string `json:"excludedTools,omitzero"` // Map of feature-flag IDs to their boolean enabled state. FeatureFlags map[string]bool `json:"featureFlags,omitzero"` + // Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + // grants. Available without enableConfigDiscovery or enableFileHooks, which controls + // repository-origin hooks only; hook/managed disables still apply. Relative SDK paths + // resolve once when supplied against the request's effective workingDirectory; retained + // roots do not move on cwd changes. Null and omission are equivalent; [] clears only the + // explicit SDK contribution. + HookDirectories []string `json:"hookDirectories,omitzero"` // Skill scan directories and descendants excluded from discovery. Supports `~`-relative // paths. IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` @@ -16991,6 +19854,12 @@ type SessionUpdateOptionsParams struct { // 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,omitzero"` + // Explicit discovery-only instruction roots using existing SDK instruction formats, not + // filesystem grants. Available without enableConfigDiscovery, subject to + // instruction/managed disables. Relative SDK paths resolve once when supplied against the + // request's effective workingDirectory; retained roots do not move on cwd changes. Null and + // omission are equivalent; [] clears only the explicit SDK contribution. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Stable integration identifier used for analytics and rate-limit attribution. IntegrationID *string `json:"integrationId,omitempty"` // Whether experimental capabilities are enabled. @@ -17046,7 +19915,11 @@ type SessionUpdateOptionsParams struct { ShellInitProfile *string `json:"shellInitProfile,omitempty"` // PowerShell process flags applied to built-in and user-requested shell commands. ShellProcessFlags []string `json:"shellProcessFlags,omitzero"` - // Additional directories to search for skills. + // Explicit discovery-only skill roots, not filesystem grants. Available without + // enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once + // when supplied against the request's effective workingDirectory; retained roots do not + // move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK + // contribution. SkillDirectories []string `json:"skillDirectories,omitzero"` // Whether to skip loading custom instruction sources. SkipCustomInstructions *bool `json:"skipCustomInstructions,omitempty"` @@ -17077,6 +19950,25 @@ type SessionUpdateOptionsResult struct { Success bool `json:"success"` } +// Internal absolute code-change totals reported by the owning host. +// Experimental: SessionUsageSetCodeChangesRequest is part of an experimental API and may +// change or be removed. +// Internal: SessionUsageSetCodeChangesRequest is an internal SDK API and is not part of the +// public surface. +type SessionUsageSetCodeChangesRequest struct { + // Absolute changed-file count; omission preserves the previous count. + FilesCount *float64 `json:"filesCount,omitempty"` + // Absolute added-line total, replacing the previous reading. + LinesAdded float64 `json:"linesAdded"` + // Absolute removed-line total, replacing the previous reading. + LinesRemoved float64 `json:"linesRemoved"` +} + +// Experimental: SessionUsageSetCodeChangesResult is part of an experimental API and may +// change or be removed. +type SessionUsageSetCodeChangesResult struct { +} + // Experimental: SessionWorkflowPauseAtCheckpointResult is part of an experimental API and // may change or be removed. type SessionWorkflowPauseAtCheckpointResult struct { @@ -17108,6 +20000,30 @@ type SessionWorkingDirectoryContext struct { RepositoryHost *string `json:"repositoryHost,omitempty"` } +// A working-directory context together with the client that produced it. +// Experimental: SessionWorkingDirectoryContextWithClient is part of an experimental API and +// may change or be removed. +type SessionWorkingDirectoryContextWithClient struct { + // Merge-base commit SHA + BaseCommit *string `json:"baseCommit,omitempty"` + // Current git branch name + Branch *string `json:"branch,omitempty"` + // Name of the client that created the session + ClientName *string `json:"clientName,omitempty"` + // Current working directory path + Cwd string `json:"cwd"` + // Root directory of the git repository + GitRoot *string `json:"gitRoot,omitempty"` + // Head commit of the current git branch + HeadCommit *string `json:"headCommit,omitempty"` + // Hosting platform type of the repository + HostType *string `json:"hostType,omitempty"` + // Repository identifier derived from the git remote URL + Repository *string `json:"repository,omitempty"` + // Raw host string from the git remote URL + RepositoryHost *string `json:"repositoryHost,omitempty"` +} + // Experimental: SessionWorkspacesCreateDirectoryResult is part of an experimental API and // may change or be removed. type SessionWorkspacesCreateDirectoryResult struct { @@ -17146,6 +20062,10 @@ func (RawSettableAuthInfoData) settableAuthInfo() {} func (r RawSettableAuthInfoData) settableAuthInfoType() SettableAuthInfoType { return r.Discriminator } +func (AccountAuthInfo) settableAuthInfo() {} +func (AccountAuthInfo) settableAuthInfoType() SettableAuthInfoType { + return SettableAuthInfoTypeAccount +} func (APIKeyAuthInfo) settableAuthInfo() {} func (APIKeyAuthInfo) settableAuthInfoType() SettableAuthInfoType { return SettableAuthInfoTypeAPIKey @@ -17190,6 +20110,18 @@ func (UserAuthInfo) settableAuthInfoType() SettableAuthInfoType { return SettableAuthInfoTypeUser } +// Outcome of an atomic user or repository settings edit. +// Experimental: SettingsEditResult is part of an experimental API and may change or be +// removed. +// Internal: SettingsEditResult is an internal SDK API and is not part of the public surface. +type SettingsEditResult struct { + // Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O + // errors remain RPC errors. + // Internal: Status is part of the SDK's internal API surface and is not intended for + // external use. + Status SettingsEditStatus `json:"status"` +} + // User-requested shell execution cancellation handle. // Experimental: ShellCancelUserRequestedRequest is part of an experimental API and may // change or be removed. @@ -18032,8 +20964,8 @@ type SkillPlanUninstallRequest struct { PolicySessionID string `json:"policySessionId"` } -// Catalog-only metadata for one SDK-provided skill. The complete SKILL.md is fetched -// separately and lazily. +// Authoritative catalog metadata for one SDK-provided skill. The skill's SKILL.md text is +// fetched separately and lazily. // Experimental: SkillProviderDescriptor is part of an experimental API and may change or be // removed. type SkillProviderDescriptor struct { @@ -18081,15 +21013,18 @@ type SkillProviderReadRequest struct { SessionID string `json:"sessionId"` } -// Complete text-only SKILL.md content returned by an SDK session's skill provider. Related -// files and assets are not supported. +// Text-only SKILL.md content returned by an SDK session's skill provider. YAML frontmatter +// is optional: fields it omits come from the catalog descriptor, fields it declares must +// match the descriptor, and `allowed-tools` is read only from frontmatter. Related files +// and assets are not supported. // Experimental: SkillProviderReadResult is part of an experimental API and may change or be // removed. // Internal: SkillProviderReadResult is an internal SDK API and is not part of the public // surface. type SkillProviderReadResult struct { - // Complete SKILL.md text. The runtime enforces a 1 MiB UTF-8 byte limit. - Markdown string `json:"markdown"` + // SKILL.md text, with or without YAML frontmatter, or null when the provider has no skill + // with the requested name. The runtime enforces a 1 MiB UTF-8 byte limit. + Markdown *string `json:"markdown"` } // Skill names to mark as disabled in global configuration, replacing any previous list. @@ -18140,7 +21075,10 @@ type SkillsDiscoverRequest struct { IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` // Optional list of project directory paths to scan for project-scoped skills ProjectPaths []string `json:"projectPaths,omitzero"` - // Optional list of additional skill directory paths to include + // Explicit discovery-only skill roots, not filesystem grants. Available without ambient + // discovery, subject to skill/managed disables. Relative paths resolve against the + // request's effective working directory when supplied. Null and omission are equivalent; an + // empty array contributes no explicit roots. SkillDirectories []string `json:"skillDirectories,omitzero"` } @@ -18178,6 +21116,11 @@ type SkillsGetDiscoveryPathsRequest struct { // Optional list of project directory paths. When omitted or empty, only personal and custom // directories are returned. ProjectPaths []string `json:"projectPaths,omitzero"` + // Explicit discovery-only skill roots to enumerate, including configured missing + // directories. Relative paths resolve against the request's effective working directory + // when supplied. These are not filesystem grants or preferred creation targets. Null and + // omission are equivalent. + SkillDirectories []string `json:"skillDirectories,omitzero"` } // Skills invoked during this session, ordered by invocation time (most recent last). @@ -19309,6 +22252,13 @@ type ToolsGetCurrentMetadataResult struct { type ToolsInitializeAndValidateResult struct { } +// No parameters; returns the external tool calls of the session and its sub-agents that are +// still waiting for a result. +// Experimental: ToolsListPendingRequestsRequest is part of an experimental API and may +// change or be removed. +type ToolsListPendingRequestsRequest struct { +} + // Optional model identifier whose tool overrides should be applied to the listing. // Experimental: ToolsListRequest is part of an experimental API and may change or be // removed. @@ -19859,6 +22809,9 @@ type UsageGetMetricsResult struct { // Per-agent usage metrics, keyed by agent instance identifier. The main conversation uses // the stable key `main`. AgentMetrics map[string]UsageMetricsAgentMetric `json:"agentMetrics,omitzero"` + // Completeness of totalNanoAiu. Numeric totals remain the reported subtotal; zero is not a + // claim of free usage when unavailable. + AiCreditsStatus *AiCreditsStatus `json:"aiCreditsStatus,omitempty"` // Aggregated code change metrics CodeChanges UsageMetricsCodeChanges `json:"codeChanges"` // Currently active model identifier @@ -19869,6 +22822,9 @@ type UsageGetMetricsResult struct { LastCallOutputTokens int64 `json:"lastCallOutputTokens"` // Per-model token and request metrics, keyed by model identifier ModelMetrics map[string]UsageMetricsModelMetric `json:"modelMetrics"` + // Provider-attributed model metrics, ordered by first observed provider and model. + // Null attribution preserves historical usage whose provider or model was not recorded. + ProviderModelMetrics []UsageMetricsProviderModelMetric `json:"providerModelMetrics,omitzero"` // ISO 8601 timestamp when the session started SessionStartTime time.Time `json:"sessionStartTime"` // Session-wide per-token-type accumulated token counts @@ -19923,6 +22879,9 @@ type UsageMetricsCodeChanges struct { // Experimental: UsageMetricsModelMetric is part of an experimental API and may change or be // removed. type UsageMetricsModelMetric struct { + // Completeness of this model's reported AI-credit subtotal. Explicitly reported zero is + // complete, not unavailable. + AiCreditsStatus *AiCreditsStatus `json:"aiCreditsStatus,omitempty"` // Latest known prompt-cache expiration for this model. A timestamp in the past indicates // that the observed cache has expired. CacheExpiresAt *time.Time `json:"cacheExpiresAt,omitempty"` @@ -19970,6 +22929,22 @@ type UsageMetricsModelMetricUsage struct { ReasoningTokens *int64 `json:"reasoningTokens,omitempty"` } +// Usage for one recorded provider and model, without merging identical model IDs across +// providers. +// Experimental: UsageMetricsProviderModelMetric is part of an experimental API and may +// change or be removed. +type UsageMetricsProviderModelMetric struct { + // Request, token, and cost totals for this provider/model. + Metrics UsageMetricsModelMetric `json:"metrics"` + // Model display name captured at call time, when known. + ModelDisplayName *string `json:"modelDisplayName,omitempty"` + // Model identity, or null for legacy aggregate-only usage. + ModelID *string `json:"modelId"` + // Provider identity and product label captured when the call was dispatched; null when + // unknown. + Provider *ModelProviderRef `json:"provider"` +} + // Session-wide token-detail entry containing the accumulated token count for one token type. // Experimental: UsageMetricsTokenDetail is part of an experimental API and may change or be // removed. @@ -19978,6 +22953,20 @@ type UsageMetricsTokenDetail struct { TokenCount int64 `json:"tokenCount"` } +// Internal absolute code-change totals reported by the owning host. +// Experimental: UsageSetCodeChangesRequest is part of an experimental API and may change or +// be removed. +// Internal: UsageSetCodeChangesRequest is an internal SDK API and is not part of the public +// surface. +type UsageSetCodeChangesRequest struct { + // Absolute changed-file count; omission preserves the previous count. + FilesCount *float64 `json:"filesCount,omitempty"` + // Absolute added-line total, replacing the previous reading. + LinesAdded float64 `json:"linesAdded"` + // Absolute removed-line total, replacing the previous reading. + LinesRemoved float64 `json:"linesRemoved"` +} + // Result of a user-requested shell command. // Experimental: UserRequestedShellCommandResult is part of an experimental API and may // change or be removed. @@ -20010,9 +22999,115 @@ type UserSettingMetadata struct { Value any `json:"value"` } -// Per-key metadata for every known user setting (settings.json overlaid with the legacy -// config.json, config.json wins), including settings left at their default. Excludes -// repository- and enterprise-managed overrides. +// A single top-level setting subtree to validate and write. +// Experimental: UserSettingsApplyTopKeyRequest is part of an experimental API and may +// change or be removed. +type UserSettingsApplyTopKeyRequest struct { + // Canonical path of the setting the caller is editing. Currently informational only. + CanonicalPath []string `json:"canonicalPath"` + // Records that the user chose an update channel explicitly, so the one-time staff channel + // migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + CompleteStaffUpdateChannelMigration *bool `json:"completeStaffUpdateChannelMigration,omitempty"` + // True to remove the top-level key instead of writing it. + Delete *bool `json:"delete,omitempty"` + // Top-level setting name to write. + TopKey string `json:"topKey"` + // Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null + // is preserved and validated as null. + Value *any `json:"value,omitempty"` +} + +// Outcome of validating and writing one top-level setting subtree. +// Experimental: UserSettingsApplyTopKeyResult is part of an experimental API and may change +// or be removed. +type UserSettingsApplyTopKeyResult struct { + // Why the write failed, present only when `status` is `write-error`. + Error *string `json:"error,omitempty"` + // Problems found, present only when `status` is `validation-error`. + Issues []UserSettingsValidationIssue `json:"issues,omitzero"` + // `ok` when the value was written, `validation-error` when it was rejected before any + // write, `write-error` when validation passed but the write failed. + Status string `json:"status"` +} + +// The overrides and host context to resolve effective runtime settings from. +// Experimental: UserSettingsBuildRuntimeRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsBuildRuntimeRequest is an internal SDK API and is not part of the +// public surface. +type UserSettingsBuildRuntimeRequest struct { + // The environment to read settings-bearing variables from. Passed explicitly rather than + // read from the server process so a host can resolve settings for an environment it is + // about to create rather than the one it runs in. + Environment map[string]string `json:"environment"` + // Settings that take precedence over every document and environment layer, such as the + // values a host derived from its own command line. Keyed by setting name, with each value + // carried verbatim, so a host may pass keys this runtime does not recognize. Absent when + // the host contributes no overrides of its own. + Overrides map[string]any `json:"overrides,omitzero"` + // The platform to apply platform-specific defaults for, in the same spelling the host's own + // runtime reports. + Platform string `json:"platform"` + // The directory the settings are being resolved for. This selects the repository-scoped + // document, so a host resolving settings for a directory other than its own process working + // directory must pass that directory here. + WorkingDirectory string `json:"workingDirectory"` +} + +// The effective runtime settings, keyed by setting name. Keys this runtime does not +// recognize are preserved rather than dropped, so a caller reading a document written by a +// newer runtime keeps every value. +// Experimental: UserSettingsBuildRuntimeResult is part of an experimental API and may +// change or be removed. +type UserSettingsBuildRuntimeResult map[string]any + +// One atomic edit of a canonical setting in settings.json. +// Experimental: UserSettingsEditRequest is part of an experimental API and may change or be +// removed. +// Internal: UserSettingsEditRequest is an internal SDK API and is not part of the public +// surface. +type UserSettingsEditRequest struct { + // Nonempty canonical path segments of the setting to edit, starting with its top-level key. + CanonicalPath []string `json:"canonicalPath"` + // Configuration directory to edit. Omitted or empty resolves the server's own home, as in + // `user.settings.loadForConfigDir`. + ConfigDir *string `json:"configDir,omitempty"` + // Set a scalar, add or remove a string list item, or remove the setting. The handler + // rejects a missing or incompatible value. + // Internal: Operation is part of the SDK's internal API surface and is not intended for + // external use. + Operation SettingsEditOperation `json:"operation"` + // Required boolean, string or number for set, required string for add-item and remove-item, + // and forbidden for remove. The runtime rejects all other JSON values. + Value any `json:"value,omitempty"` +} + +// Selects which settings file paths to resolve. +// Experimental: UserSettingsGetPathsRequest is part of an experimental API and may change +// or be removed. +type UserSettingsGetPathsRequest struct { + // Absolute path of a repository root. Supply it to also resolve that repository's two + // settings file paths; omit it to resolve only the user path. + RepoRoot *string `json:"repoRoot,omitempty"` +} + +// On-disk locations of the settings files this runtime reads. A path is reported whether or +// not the file exists. +// Experimental: UserSettingsGetPathsResult is part of an experimental API and may change or +// be removed. +type UserSettingsGetPathsResult struct { + // The repository's local, untracked settings file, or null when no repository root was + // supplied. + RepoLocalSettings *string `json:"repoLocalSettings,omitempty"` + // The repository's checked-in settings file, or null when no repository root was supplied. + RepoSettings *string `json:"repoSettings,omitempty"` + // The user settings file: `settings.json` under the resolved Copilot home. This is the file + // `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + UserSettings string `json:"userSettings"` +} + +// Per-key metadata for every known user setting in settings.json, including settings left +// at their default. Excludes repository- and enterprise-managed overrides. // Experimental: UserSettingsGetResult is part of an experimental API and may change or be // removed. type UserSettingsGetResult struct { @@ -20021,9 +23116,416 @@ type UserSettingsGetResult struct { Settings map[string]UserSettingMetadata `json:"settings"` } -// Experimental: UserSettingsReloadResult is part of an experimental API and may change or +// Top-level user-setting keys grouped by who may govern them. +// Experimental: UserSettingsGovernanceKeysResult is part of an experimental API and may +// change or be removed. +type UserSettingsGovernanceKeysResult struct { + // Top-level keys a repository may override through a Claude-compatible repository config. + ClaudeRepo []string `json:"claudeRepo"` + // Top-level keys an enterprise policy may fix through managed settings. + Managed []string `json:"managed"` + // Top-level keys a repository may override through `.github/copilot/settings.json` or + // `.github/copilot/settings.local.json`. + Repo []string `json:"repo"` +} + +// The filesystem and environment facts a user-settings file is resolved from. Passed +// explicitly rather than read from the runtime's own process, so a host whose configuration +// directory differs from its process environment resolves the file it means. +// Experimental: UserSettingsHostContext is part of an experimental API and may change or be +// removed. +type UserSettingsHostContext struct { + // The Copilot configuration directory, when the host set one. Takes precedence over + // `COPILOT_HOME` and the home directory. + ConfigDir *string `json:"configDir,omitempty"` + // The host's environment variables. `COPILOT_HOME` is read from here, as are the variables + // a settings hook may expand. + Environment any `json:"environment"` + // The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` + // is set. + HomeDirectory string `json:"homeDirectory"` +} + +// A repository to read settings from, and the user layer they are merged over. +// Experimental: UserSettingsLoadAndMergeRepoRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsLoadAndMergeRepoRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsLoadAndMergeRepoRequest struct { + // Absolute path of the repository root whose settings to read. When this is the user's home + // directory, the Claude-compatible configuration is skipped, so a home-directory session + // does not inherit a personal config as if it were repository policy. + RepoRoot string `json:"repoRoot"` + // The user's own settings, keyed by setting name. The repository layer is merged over this; + // a repository may only add to the collection settings it is allowed to influence, so a + // user setting it does not name survives unchanged. + UserSettings map[string]any `json:"userSettings"` +} + +// The settings a consumer should act on inside a repository, together with any diagnostic +// raised while reading the repository layer. +// Experimental: UserSettingsLoadAndMergeRepoResult is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsLoadAndMergeRepoResult is an internal SDK API and is not part of +// the public surface. +type UserSettingsLoadAndMergeRepoResult struct { + // The merged settings document, keyed by setting name. Equals the supplied user layer when + // the repository declares no settings. + Settings map[string]any `json:"settings"` + // Why part of the repository document was ignored, as a single human-readable string + // joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did + // load are still merged, so a consumer should surface this and continue rather than treat + // it as a failure. + Warning *string `json:"warning,omitempty"` +} + +// Selects the configuration directory whose user settings to read. +// Experimental: UserSettingsLoadForConfigDirRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsLoadForConfigDirRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsLoadForConfigDirRequest struct { + // Copilot configuration directory to read the settings document from, taking precedence + // over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, + // to read the directory the server resolved for itself. + ConfigDir *string `json:"configDir,omitempty"` +} + +// The stored user settings document, keyed by setting name. +// Experimental: UserSettingsLoadForConfigDirResult is part of an experimental API and may +// change or be removed. +type UserSettingsLoadForConfigDirResult map[string]any + +// Contents of settings.json as stored, for a caller about to rewrite it. +// Experimental: UserSettingsLoadForEditResult is part of an experimental API and may change +// or be removed. +type UserSettingsLoadForEditResult struct { + // Parsed contents, present only when `status` is `ok`. + Settings any `json:"settings,omitempty"` + // `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file + // exists but will not parse. + Status string `json:"status"` +} + +// Selects the repository whose checked-in settings to read. +// Experimental: UserSettingsLoadRepoRequest is part of an experimental API and may change +// or be removed. +type UserSettingsLoadRepoRequest struct { + // Absolute path of the repository root whose settings to read. When this is the user's home + // directory, the Claude-compatible configuration is skipped, so a home-directory session + // does not inherit a personal config as if it were repository policy. + RepoRoot string `json:"repoRoot"` +} + +// A repository's settings as stored, together with any diagnostic raised while reading them. +// Experimental: UserSettingsLoadRepoResult is part of an experimental API and may change or // be removed. -type UserSettingsReloadResult struct { +type UserSettingsLoadRepoResult struct { + // The repository's settings document, keyed by setting name, with each value carried + // verbatim. Null when the repository declares no settings. + Settings map[string]any `json:"settings,omitzero"` + // Why part of the document was ignored, as a single human-readable string joining every + // diagnostic with `; `. Null when the document loaded cleanly. The settings that did load + // are still reported, so a consumer should surface this and continue rather than treat it + // as a failure. + Warning *string `json:"warning,omitempty"` +} + +// The user's stored settings, together with any diagnostic raised while reading them. +// Experimental: UserSettingsLoadWithWarningResult is part of an experimental API and may +// change or be removed. +type UserSettingsLoadWithWarningResult struct { + // The stored user settings document, keyed by setting name, with each value carried + // verbatim. Empty when the file could not be read at all. + Settings map[string]any `json:"settings"` + // Why part of the document was ignored, phrased for display to the user. Null when the + // document loaded cleanly. The settings that did load are still reported, so a consumer may + // surface this and continue rather than treat it as a failure. + Warning *string `json:"warning,omitempty"` +} + +// The managed (enterprise policy) layer and the user layer to fold together. The field +// names carry the layer identity: nothing about a settings object identifies which layer +// produced it, so a generic base/override pair would let a caller transpose them and +// silently resolve the governance keys in the user's favour. +// Experimental: UserSettingsMergeManagedAndUserParams is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsMergeManagedAndUserParams is an internal SDK API and is not part of +// the public surface. +type UserSettingsMergeManagedAndUserParams struct { + // The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and + // `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted + // when the host is unmanaged. + Managed any `json:"managed,omitempty"` + // The user's own settings layer. Wins on every key the managed layer does not govern. + // Omitted when the user has no settings yet. + User any `json:"user,omitempty"` +} + +// The user layer folded over the managed layer. +// Experimental: UserSettingsMergeManagedAndUserResult is part of an experimental API and +// may change or be removed. +type UserSettingsMergeManagedAndUserResult struct { + // The merged settings. An empty object when neither layer was supplied, so an unmanaged + // host with no user settings governs nothing. + SettingsJSON any `json:"settingsJson"` +} + +// The user layer and the repository layer to fold together. +// Experimental: UserSettingsMergeRepoValueParams is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsMergeRepoValueParams is an internal SDK API and is not part of the +// public surface. +type UserSettingsMergeRepoValueParams struct { + // The repository's checked-in settings layer. + RepoSettings any `json:"repoSettings"` + // The user's settings, already resolved against any managed layer. + UserSettings any `json:"userSettings"` +} + +// The repository layer folded into the user layer. +// Experimental: UserSettingsMergeRepoValueResult is part of an experimental API and may +// change or be removed. +type UserSettingsMergeRepoValueResult struct { + // The merged settings, with the per-entry managed control maps re-stamped from the + // runtime's ambient managed policy. + SettingsJSON any `json:"settingsJson"` +} + +// Selects the configuration directory whose settings document to clean. +// Experimental: UserSettingsMigrateObsoleteOnDiskRequest is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsMigrateObsoleteOnDiskRequest is an internal SDK API and is not part +// of the public surface. +type UserSettingsMigrateObsoleteOnDiskRequest struct { + // The configuration directory holding the settings document to clean. A host that scopes a + // session to its own Copilot home passes that directory here; omit it to clean the document + // under the home the server resolved for itself. The home directory and environment are + // deliberately not caller-supplied: they decide only the settings path root and the two + // hook-parsing flags, and those describe the process doing the reading rather than the + // caller. + ConfigDir *string `json:"configDir,omitempty"` +} + +// The outcome of the one-time obsolete-settings cleanup. +// Experimental: UserSettingsMigrateObsoleteOnDiskResult is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsMigrateObsoleteOnDiskResult is an internal SDK API and is not part +// of the public surface. +type UserSettingsMigrateObsoleteOnDiskResult struct { + // What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not + // returned here: the document is written before this replies, so `user.settings.load` reads + // it authoritatively. + // Internal: Status is part of the SDK's internal API surface and is not intended for + // external use. + Status UserSettingsMigrateObsoleteOnDiskStatus `json:"status"` +} + +// Selects the configuration directory to run the one-time staff log-level migration +// against, and supplies the caller's record of whether it has already run. +// Experimental: UserSettingsMigrateStaffLogLevelOnceRequest is part of an experimental API +// and may change or be removed. +// Internal: UserSettingsMigrateStaffLogLevelOnceRequest is an internal SDK API and is not +// part of the public surface. +type UserSettingsMigrateStaffLogLevelOnceRequest struct { + // When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets + // the runtime answer `current` without re-running the evaluation. + CachedCompletedAt *string `json:"cachedCompletedAt,omitempty"` + // The configuration directory, home directory and environment to resolve the settings and + // global-state documents from. A host that scopes a session to its own Copilot home must + // pass that directory here, or the migration is evaluated against the server's own home + // instead. + Context UserSettingsHostContext `json:"context"` +} + +// The outcome of the one-time staff log-level migration. +// Experimental: UserSettingsMigrateStaffLogLevelOnceResult is part of an experimental API +// and may change or be removed. +// Internal: UserSettingsMigrateStaffLogLevelOnceResult is an internal SDK API and is not +// part of the public surface. +type UserSettingsMigrateStaffLogLevelOnceResult struct { + // When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for + // `ineligible`, which records nothing. + CompletedAt *string `json:"completedAt,omitempty"` + // The settings document as it stands after the migration, keyed by setting name. Present + // only for `refreshed`, and only when the document could be re-read cleanly. + Settings any `json:"settings,omitempty"` + // What the migration did. Only `refreshed` can have changed the persisted settings. + Status StaffLogLevelMigrationStatus `json:"status"` +} + +// The outcome of the one-time staff update-channel migration. +// Experimental: UserSettingsMigrateStaffUpdateChannelOnceResult is part of an experimental +// API and may change or be removed. +// Internal: UserSettingsMigrateStaffUpdateChannelOnceResult is an internal SDK API and is +// not part of the public surface. +type UserSettingsMigrateStaffUpdateChannelOnceResult struct { + // When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for + // `ineligible`, which records nothing. + CompletedAt *string `json:"completedAt,omitempty"` + // What the migration did. Only `migrated` means the persisted settings changed. + Status StaffUpdateChannelMigrationStatus `json:"status"` +} + +// Settings object whose key names should be canonicalized. +// Experimental: UserSettingsNormalizeRequest is part of an experimental API and may change +// or be removed. +type UserSettingsNormalizeRequest struct { + // Free-form settings object, possibly using legacy or snake_case key names. + Settings any `json:"settings"` +} + +// Settings object with canonical key names. +// Experimental: UserSettingsNormalizeResult is part of an experimental API and may change +// or be removed. +type UserSettingsNormalizeResult struct { + // The same settings with every legacy or snake_case key renamed to its canonical spelling. + Settings any `json:"settings"` +} + +// The on-disk location of the user's settings document. +// Experimental: UserSettingsPathResult is part of an experimental API and may change or be +// removed. +type UserSettingsPathResult struct { + // Absolute path to the settings file this runtime reads and writes. Normally + // `settings.json` under the Copilot configuration directory; an extensionless legacy + // `settings` file is reported instead when it exists and `settings.json` does not. + Path string `json:"path"` +} + +// One setting that will not take effect, and why. +// Experimental: UserSettingsProblem is part of an experimental API and may change or be +// removed. +type UserSettingsProblem struct { + // Coarse grouping for the problem, for a caller that presents problems in sections. + Category string `json:"category"` + // Why the setting will not take effect. Never contains the setting's value, which may be a + // token or another secret. + Explanation string `json:"explanation"` + // Stable identifier for this problem within the reported set, so a caller can track a + // selection across refreshes. + ID string `json:"id"` + // What is wrong in machine-readable form, for a caller that wants to branch rather than + // display. + Kind string `json:"kind"` + // The offending key as written in the file, when the problem is attributable to a single + // key. Absent when the whole file is at fault. + RawKey *string `json:"rawKey,omitempty"` + // The settings layer the problem was found in. + Source UserSettingsProblemLocation `json:"source"` +} + +// The settings layer a problem was found in. +// Experimental: UserSettingsProblemLocation is part of an experimental API and may change +// or be removed. +type UserSettingsProblemLocation struct { + // Absolute path of the file backing this layer. + FilePath string `json:"filePath"` + // Which layer this is: `user`, `repo`, or `local`. + Kind string `json:"kind"` + // The caller-supplied display label for the layer. + Label string `json:"label"` +} + +// One already-loaded settings layer to diagnose. +// Experimental: UserSettingsProblemSource is part of an experimental API and may change or +// be removed. +type UserSettingsProblemSource struct { + // The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or + // failed to parse. + Config map[string]any `json:"config,omitzero"` + // Absolute path of the file backing this layer. + FilePath string `json:"filePath"` + // True when the file itself failed to parse, so its keys could not be read at all. + Invalid *bool `json:"invalid,omitempty"` + // Which layer this is: `user`, `repo`, or `local`. + Kind string `json:"kind"` + // Caller-chosen display label for the layer, echoed back on each problem so a caller can + // group by layer without re-deriving its own naming. + Label string `json:"label"` +} + +// The settings layers to diagnose. +// Experimental: UserSettingsProblemsRequest is part of an experimental API and may change +// or be removed. +type UserSettingsProblemsRequest struct { + // Layers to diagnose, in the precedence order the caller applies them. + Sources []UserSettingsProblemSource `json:"sources,omitzero"` +} + +// The settings that will not take effect across the given layers. +// Experimental: UserSettingsProblemsResult is part of an experimental API and may change or +// be removed. +type UserSettingsProblemsResult struct { + // Each setting that will not take effect, and why. Empty when every layer is healthy. + Problems []UserSettingsProblem `json:"problems,omitzero"` +} + +// Selects the configuration directory to run the one-time staff model-selection reset +// against, and supplies the caller's record of whether it has already run. +// Experimental: UserSettingsResetStaffModelSelectionOnceRequest is part of an experimental +// API and may change or be removed. +// Internal: UserSettingsResetStaffModelSelectionOnceRequest is an internal SDK API and is +// not part of the public surface. +type UserSettingsResetStaffModelSelectionOnceRequest struct { + // The configuration directory, home directory and environment to resolve the settings and + // global-state documents from. A host that scopes a session to its own Copilot home must + // pass that directory here, or the reset is evaluated against the server's own home instead. + Context UserSettingsHostContext `json:"context"` + // Whether the signed-in account is a staff account. The reset applies only to staff, so + // anything other than `true` returns `didReset: false` without touching the settings + // document. + Staff *bool `json:"staff,omitempty"` + // When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or + // after the cutoff means the reset already ran and is returned unchanged. + StaffModelResetAt *string `json:"staffModelResetAt,omitempty"` +} + +// The outcome of the one-time staff model-selection reset. +// Experimental: UserSettingsResetStaffModelSelectionOnceResult is part of an experimental +// API and may change or be removed. +// Internal: UserSettingsResetStaffModelSelectionOnceResult is an internal SDK API and is +// not part of the public surface. +type UserSettingsResetStaffModelSelectionOnceResult struct { + // The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or + // after it means the reset is already done. + Cutoff string `json:"cutoff"` + // Whether the persisted model selection was cleared. Only `true` means the settings + // document changed and the host should adopt the returned settings. + DidReset bool `json:"didReset"` + // The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's + // own value back unchanged when nothing was reset. + ResetAt *string `json:"resetAt,omitempty"` + // The settings document as it stands after the reset, keyed by setting name. Present only + // when `didReset` is true. + Settings any `json:"settings,omitempty"` +} + +// One hook to disable or re-enable. +// Experimental: UserSettingsSetHookDisabledRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsSetHookDisabledRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsSetHookDisabledRequest struct { + // True adds the key to `disabledHooks`, false removes it. + Disabled bool `json:"disabled"` + // Durable content-hash key of the hook, as `hooks.loadResources` reports it. + DisableKey string `json:"disableKey"` + // Path of the settings.json to rewrite. + SettingsPath string `json:"settingsPath"` +} + +// Outcome of rewriting the `disabledHooks` setting. +// Experimental: UserSettingsSetHookDisabledResult is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsSetHookDisabledResult is an internal SDK API and is not part of the +// public surface. +type UserSettingsSetHookDisabledResult struct { + // Why the write failed. Absent when the status is `ok`. + ErrorMessage *string `json:"errorMessage,omitempty"` + // `ok` when the setting was written, `invalid` when settings.json could not be parsed and + // was left alone, `error` when the write itself failed. + Status string `json:"status"` } // Partial user settings to write to settings.json. Each top-level key is written @@ -20035,14 +23537,116 @@ type UserSettingsSetRequest struct { Settings any `json:"settings"` } -// Outcome of writing user settings. // Experimental: UserSettingsSetResult is part of an experimental API and may change or be // removed. type UserSettingsSetResult struct { - // Top-level keys whose write landed in settings.json but is shadowed by a value still - // present in the legacy config.json (config.json wins on read). The write does not take - // effect until the legacy value is removed. - ShadowedKeys []string `json:"shadowedKeys"` +} + +// Selects the configuration directory whose user settings document should be inspected for +// unrecognized top-level keys. +// Experimental: UserSettingsUnknownKeysWarningRequest is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsUnknownKeysWarningRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsUnknownKeysWarningRequest struct { + // The configuration directory, home directory and environment to resolve the settings + // document from. A host that scopes a session to its own Copilot home must pass that + // directory here, or the server's own home is inspected instead. + Context UserSettingsHostContext `json:"context"` +} + +// The unrecognized top-level keys found in the user settings document, already phrased for +// display. +// Experimental: UserSettingsUnknownKeysWarningResult is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsUnknownKeysWarningResult is an internal SDK API and is not part of +// the public surface. +type UserSettingsUnknownKeysWarningResult struct { + // The warning to show the user, naming the unrecognized keys and the file they were found + // in. Absent when every top-level key is recognized, and also when the document is missing + // or could not be read, because an unknown-key list taken from a document the runtime could + // not load would name keys that may not be there. + Warning *string `json:"warning,omitempty"` +} + +// Names the user setting to merge into, and the partial object to merge. +// Experimental: UserSettingsUpdateRequest is part of an experimental API and may change or +// be removed. +// Internal: UserSettingsUpdateRequest is an internal SDK API and is not part of the public +// surface. +type UserSettingsUpdateRequest struct { + // Copilot configuration directory to write the settings document in, taking precedence over + // the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to + // use the directory the server resolved for itself. + ConfigDir *string `json:"configDir,omitempty"` + // Top-level user-setting key to merge into, such as `extensions`. + Key string `json:"key"` + // Single-component name for the settings document at `/settings/.json`; + // path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the + // main settings document. + SubDir *string `json:"subDir,omitempty"` + // Value to store for `key`. When both the stored value and this value are objects, their + // fields are shallow-merged and fields this object does not name are preserved. Otherwise + // this value replaces the stored value. + Value any `json:"value"` +} + +// The stored value of the user setting after the merge. +// Experimental: UserSettingsUpdateResult is part of an experimental API and may change or +// be removed. +// Internal: UserSettingsUpdateResult is an internal SDK API and is not part of the public +// surface. +type UserSettingsUpdateResult struct { + // The key's stored value after the write: the merged object when both the stored value and + // the supplied value are objects, otherwise the supplied value. + Value any `json:"value"` +} + +// A single top-level setting subtree to validate. +// Experimental: UserSettingsValidateRequest is part of an experimental API and may change +// or be removed. +type UserSettingsValidateRequest struct { + // True to validate a removal of this key. The current settings file is not read. + Delete *bool `json:"delete,omitempty"` + // Top-level setting name to validate. + TopKey string `json:"topKey"` + // Value to validate. Omitted when `delete` is true. + Value any `json:"value,omitempty"` +} + +// Outcome of validating one top-level setting subtree. +// Experimental: UserSettingsValidateResult is part of an experimental API and may change or +// be removed. +type UserSettingsValidateResult struct { + // Problems found, empty when `ok` is true. + Issues []UserSettingsValidationIssue `json:"issues,omitzero"` + // True when the subtree is valid. + Ok bool `json:"ok"` +} + +// One problem found while validating a setting value. +// Experimental: UserSettingsValidationIssue is part of an experimental API and may change +// or be removed. +type UserSettingsValidationIssue struct { + // Human-readable description of the problem. + Message string `json:"message"` + // Where in the settings tree the problem sits, as object keys and array indices. The first + // element is the top-level key; a whole-value problem is reported as that single key. + Path []any `json:"path"` +} + +// The whole content to store in the user settings file. +// Experimental: UserSettingsWriteAllRequest is part of an experimental API and may change +// or be removed. +type UserSettingsWriteAllRequest struct { + // The settings object to store. It replaces the file's entire content, so a key absent here + // is removed. + Settings any `json:"settings"` +} + +// Experimental: UserSettingsWriteAllResult is part of an experimental API and may change or +// be removed. +type UserSettingsWriteAllResult struct { } // The approval to add as a session-scoped rule @@ -20975,12 +24579,29 @@ type WorkflowToolRunRequest struct { ToolCallID *string `json:"toolCallId,omitempty"` } +// Complete text used to generate one session diff. These are display contents, with the +// same text decoding as the patch, not a file-restore contract. +// Experimental: WorkspaceDiffContents is part of an experimental API and may change or be +// removed. +type WorkspaceDiffContents struct { + // Complete current text read when computing the diff. Omitted for a deleted file; an empty + // string represents an existing empty file. + After *string `json:"after,omitempty"` + // Complete text before the session first changed the file. Omitted when the file did not + // exist; an empty string represents an existing empty file. + Before *string `json:"before,omitempty"` +} + // A single changed file and its unified diff. // Experimental: WorkspaceDiffFileChange is part of an experimental API and may change or be // removed. type WorkspaceDiffFileChange struct { // Type of change represented by this file diff. ChangeType WorkspaceDiffFileChangeType `json:"changeType"` + // Full text used for this patch, only when includeContents was requested for session mode. + // Omitted for binary, oversized or unavailable contents, and for fallback results. Read + // isFallback and isTruncated before treating an absent value as a missing file. + Contents *WorkspaceDiffContents `json:"contents,omitempty"` // Unified diff content for the file. Empty when the diff was truncated. Diff string `json:"diff"` // Whether the diff content was omitted because it exceeded the per-file size limit. @@ -21093,6 +24714,11 @@ type WorkspacesDeleteAutopilotObjectiveResult struct { type WorkspacesDiffRequest struct { // When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. IgnoreWhitespace *bool `json:"ignoreWhitespace,omitempty"` + // Include the full before/after text used to compute each session diff. Defaults to false; + // true is accepted only for session mode. Existing capture/read limits still apply, and + // binary or unavailable contents are not returned. This can substantially increase response + // size. + IncludeContents *bool `json:"includeContents,omitempty"` // Diff mode requested by the client. Mode WorkspaceDiffMode `json:"mode"` } @@ -21576,6 +25202,21 @@ const ( AgentRegistrySpawnValidationErrorReasonYoloNotAllowed AgentRegistrySpawnValidationErrorReason = "yolo-not-allowed" ) +// Whether the accumulated numeric AI-credit subtotal covers the observed calls. +// Experimental: AiCreditsStatus is part of an experimental API and may change or be removed. +type AiCreditsStatus string + +const ( + // Every observed call supplied an AI-credit amount, including an explicit zero. + AiCreditsStatusComplete AiCreditsStatus = "complete" + // Some calls supplied amounts and some did not; the numeric value is only a reported + // subtotal. + AiCreditsStatusPartial AiCreditsStatus = "partial" + // No AI-credit amount was reported for the observed calls. Numeric zero is not a zero-cost + // claim. + AiCreditsStatusUnavailable AiCreditsStatus = "unavailable" +) + // Type of GitHub reference // Experimental: AttachmentGitHubReferenceType is part of an experimental API and may change // or be removed. @@ -21636,6 +25277,7 @@ const ( type AuthInfoType string const ( + AuthInfoTypeAccount AuthInfoType = "account" AuthInfoTypeAPIKey AuthInfoType = "api-key" AuthInfoTypeCopilotAPIToken AuthInfoType = "copilot-api-token" AuthInfoTypeEnv AuthInfoType = "env" @@ -21646,16 +25288,19 @@ const ( AuthInfoTypeUser AuthInfoType = "user" ) -// Terminal disposition of a login persistence attempt. +// Disposition of a login attempt, including pending user decisions. // Experimental: AuthLoginResultStatus is part of an experimental API and may change or be // removed. type AuthLoginResultStatus string const ( - // The credential was persisted and the account is signed in. + // The credential was persisted and the selected account is signed in. AuthLoginResultStatusCompleted AuthLoginResultStatus = "completed" // The user declined plaintext persistence. AuthLoginResultStatusDeclined AuthLoginResultStatus = "declined" + // Credentials are saved; select an account using a returned selectionId as advance input to + // complete sign-in. + AuthLoginResultStatusNeedsAccountSelection AuthLoginResultStatus = "needs-account-selection" // Persistence needs explicit consent to store the token in plaintext. AuthLoginResultStatusNeedsPlaintextConsent AuthLoginResultStatus = "needs-plaintext-consent" ) @@ -21720,8 +25365,8 @@ const ( AutopilotObjectiveStatusPaused AutopilotObjectiveStatus = "paused" ) -// Routing preference used when the session model is `auto`. `fast` is an integrator-only -// latency preset and is not a first-party GitHub Copilot product preference. +// Extensible routing preference for the virtual `auto` model. New identifiers must be +// advertised and enabled by the provider. `fast` is an integrator-only latency preset. // Experimental: AutoTier is part of an experimental API and may change or be removed. type AutoTier string @@ -22468,6 +26113,20 @@ const ( ConnectorConnectResultKindPending ConnectorConnectResultKind = "pending" ) +// Availability. +// Experimental: ConnectorDiscoveryAvailability is part of an experimental API and may +// change or be removed. +type ConnectorDiscoveryAvailability string + +const ( + // Disabled. + ConnectorDiscoveryAvailabilityDisabled ConnectorDiscoveryAvailability = "disabled" + // Enabled. + ConnectorDiscoveryAvailabilityEnabled ConnectorDiscoveryAvailability = "enabled" + // Unavailable. + ConnectorDiscoveryAvailabilityUnavailable ConnectorDiscoveryAvailability = "unavailable" +) + // Live MCP status of one Connector-owned runtime server. // Experimental: ConnectorMCPStatus is part of an experimental API and may change or be // removed. @@ -22876,6 +26535,32 @@ const ( ExternalToolTextResultForLlmContentTypeText ExternalToolTextResultForLlmContentType = "text" ) +// The population a feature flag is declared for, before overrides. +// Experimental: FeatureFlagAvailability is part of an experimental API and may change or be +// removed. +type FeatureFlagAvailability string + +const ( + // Enabled only for accounts that opted into experimental features. + FeatureFlagAvailabilityExperimental FeatureFlagAvailability = "experimental" + // Disabled for everyone, before any override. + FeatureFlagAvailabilityOff FeatureFlagAvailability = "off" + // Enabled for everyone, before any override. + FeatureFlagAvailabilityOn FeatureFlagAvailability = "on" + // Enabled for any staff account, GitHub or Microsoft. + FeatureFlagAvailabilityStaff FeatureFlagAvailability = "staff" + // Enabled only for staff accounts that have also opted into experimental features. + FeatureFlagAvailabilityStaffAndExperimental FeatureFlagAvailability = "staff-and-experimental" + // Enabled for GitHub staff accounts only. + FeatureFlagAvailabilityStaffGitHub FeatureFlagAvailability = "staff-github" + // Enabled for Microsoft staff accounts only. + FeatureFlagAvailabilityStaffMicrosoft FeatureFlagAvailability = "staff-microsoft" + // Enabled for staff accounts and for accounts that opted into experimental features. + FeatureFlagAvailabilityStaffOrExperimental FeatureFlagAvailability = "staff-or-experimental" + // Enabled only for accounts on the owning team. + FeatureFlagAvailabilityTeam FeatureFlagAvailability = "team" +) + // Why the runtime is requesting a GitHub credential. // Experimental: GitHubTokenAcquireReason is part of an experimental API and may change or // be removed. @@ -23243,6 +26928,87 @@ const ( LoginProviderKindProxima LoginProviderKind = "proxima" ) +// Operation to evaluate. Currently only url is supported. +type ManagedPermissionOperationKind string + +const ( + ManagedPermissionOperationKindURL ManagedPermissionOperationKind = "url" +) + +// Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves +// under managed policy, and unmanaged leaves the normal consumer permission flow in effect. +// No verdict bypasses other security controls. +// Experimental: ManagedPermissionVerdict is part of an experimental API and may change or +// be removed. +type ManagedPermissionVerdict string + +const ( + // Managed policy allows the operation, subject to other security controls. + ManagedPermissionVerdictAllow ManagedPermissionVerdict = "allow" + // Managed policy requires the consumer to obtain approval. + ManagedPermissionVerdictAsk ManagedPermissionVerdict = "ask" + // Managed policy prohibits the operation; do not offer approval. + ManagedPermissionVerdictDeny ManagedPermissionVerdict = "deny" + // Managed policy does not decide the operation; use the consumer's normal permission flow. + ManagedPermissionVerdictUnmanaged ManagedPermissionVerdict = "unmanaged" +) + +// What retrying did for one plugin required by managed settings. +// Experimental: ManagedPluginRetryStatus is part of an experimental API and may change or +// be removed. +type ManagedPluginRetryStatus string + +const ( + // The plugin was already installed and current, so nothing was done. + ManagedPluginRetryStatusAlreadyPresent ManagedPluginRetryStatus = "already_present" + // The plugin was not prepared because another session was changing plugins or the managed + // settings changed during the retry. It is prepared again before a later message. + ManagedPluginRetryStatusDeferred ManagedPluginRetryStatus = "deferred" + // Checking, installing, or updating the plugin failed. See `error`. + ManagedPluginRetryStatusFailed ManagedPluginRetryStatus = "failed" + // The plugin was missing and is now installed. + ManagedPluginRetryStatusInstalled ManagedPluginRetryStatus = "installed" + // The session's managed settings do not require this plugin, so nothing was done. + ManagedPluginRetryStatusNotRequired ManagedPluginRetryStatus = "not_required" + // An update was available and is now installed. + ManagedPluginRetryStatusUpdated ManagedPluginRetryStatus = "updated" +) + +// Which layer disabled bypass-permissions mode. The layer matters because only a +// server-delivered disable is pinned to an account and can later be lifted by signing in +// elsewhere. +// Experimental: ManagedSettingsBypassDisableSource is part of an experimental API and may +// change or be removed. +type ManagedSettingsBypassDisableSource string + +const ( + // The account's server-delivered org policy disabled it. Pinned to the account named by + // `currentManagedIdentity`. + ManagedSettingsBypassDisableSourceManaged ManagedSettingsBypassDisableSource = "managed" + // The device/MDM layer disabled it. Outranks the account, so no server answer lifts it. + ManagedSettingsBypassDisableSourceMdm ManagedSettingsBypassDisableSource = "mdm" + // The user turned bypass mode off themselves. + ManagedSettingsBypassDisableSourceUser ManagedSettingsBypassDisableSource = "user" +) + +// What the managed-policy resolution said about bypass-permissions mode. `unknown` is a +// third answer rather than a missing one, and the caller must send it explicitly when it +// has no verdict. +// Experimental: ManagedSettingsBypassPolicyResolution is part of an experimental API and +// may change or be removed. +type ManagedSettingsBypassPolicyResolution string + +const ( + // The policy resolved and does not disable bypass mode. + ManagedSettingsBypassPolicyResolutionAllowed ManagedSettingsBypassPolicyResolution = "allowed" + // The policy resolved and disables bypass mode. + ManagedSettingsBypassPolicyResolutionDisabled ManagedSettingsBypassPolicyResolution = "disabled" + // No verdict: the fetch failed, or the service declared a policy this build may not + // enforce. Whatever is in force is preserved, because reverting to permissive on an + // unreadable policy would widen access. + ManagedSettingsBypassPolicyResolutionUnknown ManagedSettingsBypassPolicyResolution = "unknown" +) + // A channel accepted by managedSettings.compose. // Experimental: ManagedSettingsChannel is part of an experimental API and may change or be // removed. @@ -23269,6 +27035,46 @@ const ( ManagedSettingsDiagnosticSeverityWarning ManagedSettingsDiagnosticSeverity = "warning" ) +// Severity of a diagnostic emitted while ingesting managed settings. +// Experimental: ManagedSettingsLogLevel is part of an experimental API and may change or be +// removed. +type ManagedSettingsLogLevel string + +const ( + // Detail useful only when diagnosing an ingestion. + ManagedSettingsLogLevelDebug ManagedSettingsLogLevel = "debug" + // A failure that changed the outcome of the ingestion. + ManagedSettingsLogLevelError ManagedSettingsLogLevel = "error" + // Ordinary progress worth surfacing under a verbose flag. + ManagedSettingsLogLevelInfo ManagedSettingsLogLevel = "info" + // A condition the operator should see but which did not stop the ingestion. + ManagedSettingsLogLevelWarning ManagedSettingsLogLevel = "warning" +) + +// Which channel registered the policy helper that produced a helper layer. +// Experimental: ManagedSettingsPolicyHelperAuthority is part of an experimental API and may +// change or be removed. +type ManagedSettingsPolicyHelperAuthority string + +const ( + // The helper was registered by the device (MDM or managed file) layer. + ManagedSettingsPolicyHelperAuthorityDevice ManagedSettingsPolicyHelperAuthority = "device" + // The helper was registered by the account's server-delivered policy. + ManagedSettingsPolicyHelperAuthorityServer ManagedSettingsPolicyHelperAuthority = "server" +) + +// The operation that requires a policy-helper response. +// Experimental: ManagedSettingsPolicyHelperReason is part of an experimental API and may +// change or be removed. +type ManagedSettingsPolicyHelperReason string + +const ( + // Resolve policy before plugin activation. + ManagedSettingsPolicyHelperReasonPluginActivation ManagedSettingsPolicyHelperReason = "pluginActivation" + // Resolve policy for session startup. + ManagedSettingsPolicyHelperReasonSessionStart ManagedSettingsPolicyHelperReason = "sessionStart" +) + // Summary of which managed-settings channels contributed to the effective session policy. // Use the per-channel booleans for exact provenance. // Experimental: ManagedSettingsResolvedSource is part of an experimental API and may change @@ -23292,6 +27098,44 @@ const ( ManagedSettingsResolvedSourceServer ManagedSettingsResolvedSource = "server" ) +// How an ingestion may use the on-disk server-policy cache. +// Experimental: ManagedSettingsServerPolicyCacheMode is part of an experimental API and may +// change or be removed. +type ManagedSettingsServerPolicyCacheMode string + +const ( + // Read cached policy without a network request. + ManagedSettingsServerPolicyCacheModeCacheOnly ManagedSettingsServerPolicyCacheMode = "cacheOnly" + // Ignore the cache entirely and rely on the live fetch alone. + ManagedSettingsServerPolicyCacheModeDisabled ManagedSettingsServerPolicyCacheMode = "disabled" + // Serve a cached entry only as a fallback after a failed live fetch. + ManagedSettingsServerPolicyCacheModeFallbackOnly ManagedSettingsServerPolicyCacheMode = "fallbackOnly" + // Serve a recent cache entry before a live fetch. + ManagedSettingsServerPolicyCacheModePreferFresh ManagedSettingsServerPolicyCacheMode = "preferFresh" +) + +// How the server layer of an ingestion was resolved. +// Experimental: ManagedSettingsServerPolicyResolution is part of an experimental API and +// may change or be removed. +type ManagedSettingsServerPolicyResolution string + +const ( + // No cached policy or confirmed no-policy result exists. + ManagedSettingsServerPolicyResolutionCacheMiss ManagedSettingsServerPolicyResolution = "cacheMiss" + // No policy could be resolved and the host applies the fail-closed gates. + ManagedSettingsServerPolicyResolutionFailClosed ManagedSettingsServerPolicyResolution = "failClosed" + // No policy could be resolved and the host proceeds unmanaged. + ManagedSettingsServerPolicyResolutionFailOpen ManagedSettingsServerPolicyResolution = "failOpen" + // A live fetch failed and a cached entry was served in its place. + ManagedSettingsServerPolicyResolutionFallbackCache ManagedSettingsServerPolicyResolution = "fallbackCache" + // A recent cached entry was served without a live fetch. + ManagedSettingsServerPolicyResolutionFreshCache ManagedSettingsServerPolicyResolution = "freshCache" + // A live fetch succeeded. + ManagedSettingsServerPolicyResolutionLive ManagedSettingsServerPolicyResolution = "live" + // No fetch was attempted because no usable token was available. + ManagedSettingsServerPolicyResolutionSkippedNoToken ManagedSettingsServerPolicyResolution = "skippedNoToken" +) + // Allowed values for the `McpAppsHostContextDetailsAvailableDisplayMode` enumeration. // Experimental: MCPAppsHostContextDetailsAvailableDisplayMode is part of an experimental // API and may change or be removed. @@ -24005,11 +27849,13 @@ const ( MCPServerConfigStdioTypeStdio MCPServerConfigStdioType = "stdio" ) -// Configuration source: user, workspace, plugin, builtin, or managed +// Configuration source: user, workspace, plugin, builtin, managed, or account // Experimental: MCPServerSource is part of an experimental API and may change or be removed. type MCPServerSource string const ( + // Server contributed by a signed-in account; enablement and organization policy still apply. + MCPServerSourceAccount MCPServerSource = "account" // Server bundled with the runtime. MCPServerSourceBuiltin MCPServerSource = "builtin" // Server supplied by a trusted host-managed catalog. @@ -24893,6 +28739,137 @@ const ( ProviderEndpointWireAPIResponses ProviderEndpointWireAPI = "responses" ) +// Identity scope of a monthly usage reading. +// Experimental: ProviderMonthlyUsageScope is part of an experimental API and may change or +// be removed. +type ProviderMonthlyUsageScope string + +const ( + // The service did not establish a recognized usage scope. + ProviderMonthlyUsageScopeUnknown ProviderMonthlyUsageScope = "unknown" + // Consumption of the authenticated user within the parent observation's service and + // returned cycle. + ProviderMonthlyUsageScopeUser ProviderMonthlyUsageScope = "user" +) + +// Availability of a service's monthly consumption reading. +// Experimental: ProviderMonthlyUsageState is part of an experimental API and may change or +// be removed. +type ProviderMonthlyUsageState string + +const ( + // The service reported a usable consumption reading, including an explicit zero. + ProviderMonthlyUsageStateAvailable ProviderMonthlyUsageState = "available" + // The service found no usage policy; no consumption amount is known. + ProviderMonthlyUsageStateNoPolicy ProviderMonthlyUsageState = "no_policy" + // The read failed or its data could not be used; consumption is unknown. + ProviderMonthlyUsageStateUnavailable ProviderMonthlyUsageState = "unavailable" + // The service reported an unrecognized usage state. + ProviderMonthlyUsageStateUnknown ProviderMonthlyUsageState = "unknown" +) + +// Access policy reported by the quota service. +// Experimental: ProviderQuotaAccessState is part of an experimental API and may change or +// be removed. +type ProviderQuotaAccessState string + +const ( + // Access is allowed. + ProviderQuotaAccessStateAllowed ProviderQuotaAccessState = "allowed" + // Access is denied. + ProviderQuotaAccessStateDenied ProviderQuotaAccessState = "denied" + // Quota is not required for this access. + ProviderQuotaAccessStateNotRequired ProviderQuotaAccessState = "not_required" + // Client-only compatibility placeholder when acquisitionStatus is unavailable or failed; + // not an observed service verdict. + ProviderQuotaAccessStateUnavailable ProviderQuotaAccessState = "unavailable" + // The service did not supply a recognized access state. + ProviderQuotaAccessStateUnknown ProviderQuotaAccessState = "unknown" +) + +// Acquisition state, independent of the service's business access/capacity verdict. +// Experimental: ProviderQuotaAcquisitionStatus is part of an experimental API and may +// change or be removed. +type ProviderQuotaAcquisitionStatus string + +const ( + // Acquisition failed; inspect httpStatus/acquisitionError without inferring a business + // verdict. + ProviderQuotaAcquisitionStatusFailed ProviderQuotaAcquisitionStatus = "failed" + // A service quota observation was received. + ProviderQuotaAcquisitionStatusSucceeded ProviderQuotaAcquisitionStatus = "succeeded" + // No service snapshot is available for this caller or surface. + ProviderQuotaAcquisitionStatusUnavailable ProviderQuotaAcquisitionStatus = "unavailable" +) + +// Capacity is independent of whether a numeric balance was supplied. +// Experimental: ProviderQuotaCapacityState is part of an experimental API and may change or +// be removed. +type ProviderQuotaCapacityState string + +const ( + // Capacity is available. + ProviderQuotaCapacityStateAvailable ProviderQuotaCapacityState = "available" + // The service explicitly reports exhaustion. + ProviderQuotaCapacityStateExhausted ProviderQuotaCapacityState = "exhausted" + // The service reports that capacity is not applicable. + ProviderQuotaCapacityStateNotApplicable ProviderQuotaCapacityState = "not_applicable" + // No billable quota is required. + ProviderQuotaCapacityStateNotRequired ProviderQuotaCapacityState = "not_required" + // Client-only compatibility placeholder when acquisitionStatus is unavailable or failed; + // not an observed service verdict. + ProviderQuotaCapacityStateUnavailable ProviderQuotaCapacityState = "unavailable" + // No recognized capacity state was supplied. + ProviderQuotaCapacityStateUnknown ProviderQuotaCapacityState = "unknown" + // The reported entitlement is unlimited. + ProviderQuotaCapacityStateUnlimited ProviderQuotaCapacityState = "unlimited" +) + +// Timing and purpose of a provider quota observation. +// Experimental: ProviderQuotaObservationKind is part of an experimental API and may change +// or be removed. +type ProviderQuotaObservationKind string + +const ( + // An explicit account read; consumption may still be subject to service aggregation delay. + ProviderQuotaObservationKindAccountSnapshot ProviderQuotaObservationKind = "account_snapshot" + // A verdict attached before an inference response. May be cached; never a post-charge + // balance. + ProviderQuotaObservationKindAdmissionState ProviderQuotaObservationKind = "admission_state" +) + +// Interpretation permitted for independently reported quantities. +// Experimental: ProviderQuotaQuantityKind is part of an experimental API and may change or +// be removed. +type ProviderQuotaQuantityKind string + +const ( + // Raw advisory quantities; do not infer permission, usage percentage, reset cadence, or + // post-charge balance. + ProviderQuotaQuantityKindAdvisoryBalance ProviderQuotaQuantityKind = "advisory_balance" + // Quantities form an authoritative available-of-entitled budget suitable for percentage + // presentation. + ProviderQuotaQuantityKindAuthoritativeBudget ProviderQuotaQuantityKind = "authoritative_budget" + // No quantity measurement, as with admission-only response headers. + ProviderQuotaQuantityKindNone ProviderQuotaQuantityKind = "none" +) + +// Units explicitly reported by a quota provider. +// Experimental: ProviderQuotaUnit is part of an experimental API and may change or be +// removed. +type ProviderQuotaUnit string + +const ( + // AI credits, not tokens or currency. + ProviderQuotaUnitAiCredits ProviderQuotaUnit = "ai_credits" + // Requests charged against an entitlement. + ProviderQuotaUnitRequests ProviderQuotaUnit = "requests" + // Model tokens. + ProviderQuotaUnitTokens ProviderQuotaUnit = "tokens" + // The observation does not establish a quantity unit. + ProviderQuotaUnitUnknown ProviderQuotaUnit = "unknown" +) + // Type of GitHub reference // Experimental: PushAttachmentGitHubReferenceType is part of an experimental API and may // change or be removed. @@ -24969,6 +28946,8 @@ const ( // Review or widen the sandbox policy. The blocked path or host is named by the accompanying // message or by the tool result the action arrived with. RemediationActionReviewSandboxPolicy RemediationAction = "review_sandbox_policy" + // Discard conversation history back through the blocked request before continuing. + RemediationActionRewindConversation RemediationAction = "rewind_conversation" // Inspect which account is currently authenticated before deciding what to change. RemediationActionShowAccount RemediationAction = "show_account" // Authenticate again with the Copilot backend. The current credential is absent, expired, @@ -25036,6 +29015,18 @@ const ( RemoteSessionModeOn RemoteSessionMode = "on" ) +// Which repository settings file to edit. +// Experimental: RepoSettingsEditScope is part of an experimental API and may change or be +// removed. +type RepoSettingsEditScope string + +const ( + // The local repository settings file. + RepoSettingsEditScopeLocal RepoSettingsEditScope = "local" + // The shared repository settings file. + RepoSettingsEditScopeRepo RepoSettingsEditScope = "repo" +) + // Output format discriminator. Currently only json_schema is supported. type ResponseFormatType string @@ -25409,6 +29400,30 @@ const ( SessionOpenParamsKindResumeLast SessionOpenParamsKind = "resumeLast" ) +// Copilot plan tier used by the session quota projection. +// Experimental: SessionQuotaPlanTier is part of an experimental API and may change or be +// removed. +type SessionQuotaPlanTier string + +const ( + // Copilot Business. + SessionQuotaPlanTierBusiness SessionQuotaPlanTier = "business" + // Copilot education entitlement. + SessionQuotaPlanTierEdu SessionQuotaPlanTier = "edu" + // Copilot Enterprise. + SessionQuotaPlanTierEnterprise SessionQuotaPlanTier = "enterprise" + // Copilot Free. + SessionQuotaPlanTierFree SessionQuotaPlanTier = "free" + // Copilot Max. + SessionQuotaPlanTierMax SessionQuotaPlanTier = "max" + // Copilot Pro. + SessionQuotaPlanTierPro SessionQuotaPlanTier = "pro" + // Copilot Pro+. + SessionQuotaPlanTierProPlus SessionQuotaPlanTier = "pro_plus" + // The account's plan tier is not known. + SessionQuotaPlanTierUnknown SessionQuotaPlanTier = "unknown" +) + // Status discriminator for SessionsClientMetadataEntry. type SessionsClientMetadataEntryStatus string @@ -25572,6 +29587,7 @@ const ( type SettableAuthInfoType string const ( + SettableAuthInfoTypeAccount SettableAuthInfoType = "account" SettableAuthInfoTypeAPIKey SettableAuthInfoType = "api-key" SettableAuthInfoTypeCopilotAPIToken SettableAuthInfoType = "copilot-api-token" SettableAuthInfoTypeEnv SettableAuthInfoType = "env" @@ -25581,6 +29597,36 @@ const ( SettableAuthInfoTypeUser SettableAuthInfoType = "user" ) +// One atomic settings mutation. +// Experimental: SettingsEditOperation is part of an experimental API and may change or be +// removed. +type SettingsEditOperation string + +const ( + // Add one string to a list, unless present. + SettingsEditOperationAddItem SettingsEditOperation = "add-item" + // Remove the setting without supplying a value. + SettingsEditOperationRemove SettingsEditOperation = "remove" + // Remove one string from a list, unless absent. + SettingsEditOperationRemoveItem SettingsEditOperation = "remove-item" + // Set one scalar value. + SettingsEditOperationSet SettingsEditOperation = "set" +) + +// Whether one atomic settings edit changed a file. +// Experimental: SettingsEditStatus is part of an experimental API and may change or be +// removed. +type SettingsEditStatus string + +const ( + // The edit changed the setting and was stored. + SettingsEditStatusChanged SettingsEditStatus = "changed" + // The existing settings file could not be edited safely; nothing was written. + SettingsEditStatusInvalid SettingsEditStatus = "invalid" + // The setting already had the requested state. + SettingsEditStatusUnchanged SettingsEditStatus = "unchanged" +) + // Controls automatic non-interactive profile loading where supported. Explicit initScripts // are unaffected. // Experimental: ShellInitProfile is part of an experimental API and may change or be @@ -25890,6 +29936,45 @@ const ( SlashCommandModelPickerDialogKindModelPicker SlashCommandModelPickerDialogKind = "model-picker" ) +// What the one-time staff log-level migration did. +// Experimental: StaffLogLevelMigrationStatus is part of an experimental API and may change +// or be removed. +type StaffLogLevelMigrationStatus string + +const ( + // The migration already ran; the stored completion timestamp is returned unchanged. + StaffLogLevelMigrationStatusCurrent StaffLogLevelMigrationStatus = "current" + // The account is not a staff account, so the migration does not apply and nothing was + // recorded. + StaffLogLevelMigrationStatusIneligible StaffLogLevelMigrationStatus = "ineligible" + // The migration ran now. The persisted settings may have changed, so the host should adopt + // the returned settings when they are present. + StaffLogLevelMigrationStatusRefreshed StaffLogLevelMigrationStatus = "refreshed" +) + +// What the one-time staff update-channel migration did. +// Experimental: StaffUpdateChannelMigrationStatus is part of an experimental API and may +// change or be removed. +type StaffUpdateChannelMigrationStatus string + +const ( + // The persisted channel was already stable, so nothing changed, but the migration is now + // recorded as done. + StaffUpdateChannelMigrationStatusCompleted StaffUpdateChannelMigrationStatus = "completed" + // The migration already ran within the cutoff window; the stored completion timestamp is + // returned unchanged. + StaffUpdateChannelMigrationStatusCurrent StaffUpdateChannelMigrationStatus = "current" + // The account is on the experimental channel, which the migration deliberately leaves + // alone, and the migration is recorded as done. + StaffUpdateChannelMigrationStatusExcludedExperimental StaffUpdateChannelMigrationStatus = "excluded-experimental" + // The account is not a staff account, so the migration does not apply and nothing was + // recorded. + StaffUpdateChannelMigrationStatusIneligible StaffUpdateChannelMigrationStatus = "ineligible" + // The persisted update channel was changed to stable. Only this outcome requires the host + // to reload its configuration. + StaffUpdateChannelMigrationStatusMigrated StaffUpdateChannelMigrationStatus = "migrated" +) + // Context tier override for matching subagents // Experimental: SubagentSettingsEntryContextTier is part of an experimental API and may // change or be removed. @@ -26216,6 +30301,23 @@ const ( UISessionLimitsExhaustedResponseActionUnset UISessionLimitsExhaustedResponseAction = "unset" ) +// What the one-time obsolete-settings cleanup did to the document. +// Experimental: UserSettingsMigrateObsoleteOnDiskStatus is part of an experimental API and +// may change or be removed. +type UserSettingsMigrateObsoleteOnDiskStatus string + +const ( + // Obsolete keys were removed and the document was rewritten. + UserSettingsMigrateObsoleteOnDiskStatusChanged UserSettingsMigrateObsoleteOnDiskStatus = "changed" + // The document could not be parsed, so it was left untouched rather than rewritten from a + // partial read. + UserSettingsMigrateObsoleteOnDiskStatusInvalid UserSettingsMigrateObsoleteOnDiskStatus = "invalid" + // No settings document exists, so there was nothing to clean. + UserSettingsMigrateObsoleteOnDiskStatusMissing UserSettingsMigrateObsoleteOnDiskStatus = "missing" + // The document parsed and held nothing obsolete, so nothing was written. + UserSettingsMigrateObsoleteOnDiskStatusUnchanged UserSettingsMigrateObsoleteOnDiskStatus = "unchanged" +) + // Kind discriminator for UserToolSessionApproval. type UserToolSessionApprovalKind string @@ -26681,6 +30783,82 @@ func (a *ServerCommandsAPI) List(ctx context.Context) (*CommandList, error) { return &result, nil } +// Experimental: ServerConnectorsAPI contains experimental APIs that may change or be +// removed. +type ServerConnectorsAPI serverAPI + +// GetAccounts returns eligible accounts. +// +// RPC method: connectors.getAccounts. +// +// Returns: Eligible accounts. +func (a *ServerConnectorsAPI) GetAccounts(ctx context.Context) (*ConnectorDiscoveryAccountList, error) { + raw, err := a.client.Request(ctx, "connectors.getAccounts", nil) + if err != nil { + return nil, err + } + var result ConnectorDiscoveryAccountList + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetCapabilities returns feature availability. +// +// RPC method: connectors.getCapabilities. +// +// Returns: Feature availability. +func (a *ServerConnectorsAPI) GetCapabilities(ctx context.Context) (*ConnectorDiscoveryCapabilities, error) { + raw, err := a.client.Request(ctx, "connectors.getCapabilities", nil) + if err != nil { + return nil, err + } + var result ConnectorDiscoveryCapabilities + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Lists entries for the selected account. +// +// RPC method: connectors.list. +// +// Parameters: Selected account. +// +// Returns: Entries for the selected account. +func (a *ServerConnectorsAPI) List(ctx context.Context, params *ConnectorDiscoveryAccountRequest) (*ConnectorDiscoveryCatalogResult, error) { + raw, err := a.client.Request(ctx, "connectors.list", params) + if err != nil { + return nil, err + } + var result ConnectorDiscoveryCatalogResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Refreshes entries for the selected account. +// +// RPC method: connectors.refresh. +// +// Parameters: Selected account. +// +// Returns: Entries for the selected account. +func (a *ServerConnectorsAPI) Refresh(ctx context.Context, params *ConnectorDiscoveryAccountRequest) (*ConnectorDiscoveryCatalogResult, error) { + raw, err := a.client.Request(ctx, "connectors.refresh", params) + if err != nil { + return nil, err + } + var result ConnectorDiscoveryCatalogResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: ServerEnvironmentsAPI contains experimental APIs that may change or be // removed. type ServerEnvironmentsAPI serverAPI @@ -26856,6 +31034,28 @@ func (a *ServerHostAPI) Dispose(ctx context.Context, params *HostDisposeRequest) return &result, nil } +// ListSessions reads the complete advertised live and dormant session catalog of an +// existing host owned by this connection. Does not start hosting, subscribe to sessions, or +// guarantee resumability. +// +// RPC method: host.listSessions. +// +// Parameters: Reads a running host's catalog or the runtime's saved default catalog. +// +// Returns: The complete live and dormant advertised catalog, without subscribing to +// sessions. +func (a *ServerHostAPI) ListSessions(ctx context.Context, params *HostListSessionsRequest) (*HostListSessionsResult, error) { + raw, err := a.client.Request(ctx, "host.listSessions", params) + if err != nil { + return nil, err + } + var result HostListSessionsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // PublishSession publishes an attached resident session for this listener's lifetime // without copying it. // @@ -27160,6 +31360,42 @@ func (a *ServerManagedSettingsAPI) Validate(ctx context.Context, params *Managed return &result, nil } +// Experimental: ServerManagedSettingsPermissionsAPI contains experimental APIs that may +// change or be removed. +type ServerManagedSettingsPermissionsAPI serverAPI + +// Evaluate pure, sessionless evaluation of operations against a supplied +// permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission +// grants, or sandbox changes. Obtain the context from managedSettings.resolve or +// session.managedSettings.get, or reuse an in-memory context. Results preserve input order +// and duplicates. Consumers must block deny, obtain approval for ask, and use their normal +// permission flow for unmanaged. Unknown policy returns failClosed with every operation +// denied. This is not a substitute for user permissions or other security controls. +// +// RPC method: managedSettings.permissions.evaluate. +// +// Parameters: Managed policy context and ordered operations for pure, sessionless +// evaluation. +// +// Returns: Ordered managed permission verdicts and the supplied policy's fail-closed +// posture. +func (a *ServerManagedSettingsPermissionsAPI) Evaluate(ctx context.Context, params *ManagedPermissionsEvaluateRequest) (*ManagedSettingsPermissionsEvaluateResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.permissions.evaluate", params) + if err != nil { + return nil, err + } + var result ManagedSettingsPermissionsEvaluateResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Permissions returns experimental APIs that may change or be removed. +func (s *ServerManagedSettingsAPI) Permissions() *ServerManagedSettingsPermissionsAPI { + return (*ServerManagedSettingsPermissionsAPI)(s) +} + // Experimental: ServerMCPAPI contains experimental APIs that may change or be removed. type ServerMCPAPI serverAPI @@ -27875,6 +32111,48 @@ func (a *ServerSandboxAPI) GetHostSupport(ctx context.Context) (*SandboxHostSupp // removed. type ServerSandboxProxyCaAPI serverAPI +// CheckInstallationSupport reports whether this runtime process can offer installing the +// sandbox credential-proxy certificate authority into OS trust. +// +// RPC method: sandbox.proxyCa.checkInstallationSupport. +// +// Returns: True when this process can offer installing the sandbox credential-proxy +// certificate authority into OS trust. +func (a *ServerSandboxProxyCaAPI) CheckInstallationSupport(ctx context.Context) (*SandboxProxyCaCheckInstallationSupportResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxyCa.checkInstallationSupport", nil) + if err != nil { + return nil, err + } + var result SandboxProxyCaCheckInstallationSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// CheckRelevance reports whether this sandbox configuration uses the credential proxy and +// can need certificate-authority setup. +// +// RPC method: sandbox.proxyCa.checkRelevance. +// +// Parameters: Identifies the credential hosts that the persistent certificate authority of +// the sandbox credential proxy must cover. The runtime always adds the hosts from the saved +// user settings. +// +// Returns: True when the sandbox configuration uses the credential proxy and can need +// certificate-authority setup. +func (a *ServerSandboxProxyCaAPI) CheckRelevance(ctx context.Context, params *SandboxProxyCaRequest) (*SandboxProxyCaCheckRelevanceResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxyCa.checkRelevance", params) + if err != nil { + return nil, err + } + var result SandboxProxyCaCheckRelevanceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Creates the persistent certificate authority of the sandbox credential proxy if none is // stored, without changing OS trust, and returns the path of its public certificate. Keeps // an existing certificate authority, even one that must be rotated. Fails where OS trust is @@ -28820,564 +33098,3171 @@ func (a *ServerSkillsInstallationsAPI) List(ctx context.Context, params *SkillIn return result, nil } -// Recover reconciles interrupted owned Skill installation work for the selected existing -// session, then inspects owned inventory. Recovery is never gated by the Skill-install -// feature flag. +// Recover reconciles interrupted owned Skill installation work for the selected existing +// session, then inspects owned inventory. Recovery is never gated by the Skill-install +// feature flag. +// +// RPC method: skills.installations.recover. +// +// Parameters: Inventory request under an explicitly selected existing session. +// +// Returns: Skill installation management result with the honoured contract, or a typed +// refusal. +func (a *ServerSkillsInstallationsAPI) Recover(ctx context.Context, params *SkillInstallationsRequest) (SkillInstallationManagementResult, error) { + raw, err := a.client.Request(ctx, "skills.installations.recover", params) + if err != nil { + return nil, err + } + result, err := unmarshalSkillInstallationManagementResult(raw) + if err != nil { + return nil, err + } + return result, nil +} + +// SetEnabled atomically persists enablement for one owned Agent Finder Skill and reconciles +// the selected bound session. Enablement is installation-scoped by receipt identity and is +// never gated by the Skill-install feature flag. +// +// RPC method: skills.installations.setEnabled. +// +// Parameters: Persisted enablement update for one owned Skill installation. +// +// Returns: Skill installation management result with the honoured contract, or a typed +// refusal. +func (a *ServerSkillsInstallationsAPI) SetEnabled(ctx context.Context, params *SkillSetEnabledRequest) (SkillInstallationManagementResult, error) { + raw, err := a.client.Request(ctx, "skills.installations.setEnabled", params) + if err != nil { + return nil, err + } + result, err := unmarshalSkillInstallationManagementResult(raw) + if err != nil { + return nil, err + } + return result, nil +} + +// Status inspects a known Skill installation operation on its original runtime connection. +// Status is never gated by the Skill-install feature flag. +// +// RPC method: skills.installations.status. +// +// Parameters: Existing-operation control. A new session selector is deliberately not +// accepted. +// +// Returns: Skill installation management result with the honoured contract, or a typed +// refusal. +func (a *ServerSkillsInstallationsAPI) Status(ctx context.Context, params *SkillInstallationOperationRequest) (SkillInstallationManagementResult, error) { + raw, err := a.client.Request(ctx, "skills.installations.status", params) + if err != nil { + return nil, err + } + result, err := unmarshalSkillInstallationManagementResult(raw) + if err != nil { + return nil, err + } + return result, nil +} + +// Experimental: Installations returns experimental APIs that may change or be removed. +func (s *ServerSkillsAPI) Installations() *ServerSkillsInstallationsAPI { + return (*ServerSkillsInstallationsAPI)(s) +} + +// Experimental: ServerToolsAPI contains experimental APIs that may change or be removed. +type ServerToolsAPI serverAPI + +// Lists built-in tools available for a model. +// +// RPC method: tools.list. +// +// Parameters: Optional model identifier whose tool overrides should be applied to the +// listing. +// +// 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) { + raw, err := a.client.Request(ctx, "tools.list", params) + if err != nil { + return nil, err + } + var result ToolList + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: ServerUserAPI contains experimental APIs that may change or be removed. +type ServerUserAPI serverAPI + +// Experimental: ServerUserSettingsAPI contains experimental APIs that may change or be +// removed. +type ServerUserSettingsAPI serverAPI + +// Get lists every known user setting from settings.json, each with its effective value, its +// default, and whether it is at the default — so settings the user has never set still +// appear with their default value. Does not include repository- or enterprise-managed +// overrides that the runtime layers on top at session time. +// +// RPC method: user.settings.get. +// +// Returns: Per-key metadata for every known user setting in settings.json, including +// settings left at their default. Excludes repository- and enterprise-managed overrides. +func (a *ServerUserSettingsAPI) Get(ctx context.Context) (*UserSettingsGetResult, error) { + raw, err := a.client.Request(ctx, "user.settings.get", nil) + if err != nil { + return nil, err + } + var result UserSettingsGetResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Set writes one or more user settings to settings.json, replacing each provided top-level +// key. A key whose value is null is removed. +// +// RPC method: user.settings.set. +// +// Parameters: Partial user settings to write to settings.json. Each top-level key is +// written individually, replacing the existing value; a key whose value is null is removed. +func (a *ServerUserSettingsAPI) Set(ctx context.Context, params *UserSettingsSetRequest) (*UserSettingsSetResult, error) { + raw, err := a.client.Request(ctx, "user.settings.set", params) + if err != nil { + return nil, err + } + var result UserSettingsSetResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Settings returns experimental APIs that may change or be removed. +func (s *ServerUserAPI) Settings() *ServerUserSettingsAPI { + return (*ServerUserSettingsAPI)(s) +} + +// 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 + + Account *ServerAccountAPI + AgentRegistry *ServerAgentRegistryAPI + Agents *ServerAgentsAPI + Catalog *ServerCatalogAPI + Commands *ServerCommandsAPI + Connectors *ServerConnectorsAPI + Environments *ServerEnvironmentsAPI + Extensions *ServerExtensionsAPI + Hooks *ServerHooksAPI + Host *ServerHostAPI + Instructions *ServerInstructionsAPI + LlmInference *ServerLlmInferenceAPI + ManagedSettings *ServerManagedSettingsAPI + MCP *ServerMCPAPI + Models *ServerModelsAPI + Plugins *ServerPluginsAPI + Runtime *ServerRuntimeAPI + Sandbox *ServerSandboxAPI + Secrets *ServerSecretsAPI + SessionFS *ServerSessionFSAPI + Sessions *ServerSessionsAPI + Skills *ServerSkillsAPI + Tools *ServerToolsAPI + User *ServerUserAPI +} + +// Ping checks server responsiveness and returns protocol information. +// +// RPC method: ping. +// +// Parameters: Optional message to echo back to the caller. +// +// Returns: Server liveness response, including the echoed message, current server +// timestamp, and protocol version. +// Experimental: Ping is an experimental API and may change or be removed in future versions. +func (a *ServerRPC) Ping(ctx context.Context, params *PingRequest) (*PingResult, error) { + raw, err := a.common.client.Request(ctx, "ping", params) + if err != nil { + return nil, err + } + var result PingResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// RegisterExtensionLaunchProvider registers the calling SDK client as the per-entrypoint +// extension launch provider. Call before creating any sessions. When omitted, the runtime +// uses its built-in extension launcher. +// +// RPC method: registerExtensionLaunchProvider. +// Experimental: RegisterExtensionLaunchProvider is an experimental API and may change or be +// removed in future versions. +func (a *ServerRPC) RegisterExtensionLaunchProvider(ctx context.Context) (*RegisterExtensionLaunchProviderResult, error) { + raw, err := a.common.client.Request(ctx, "registerExtensionLaunchProvider", nil) + if err != nil { + return nil, err + } + var result RegisterExtensionLaunchProviderResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + 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.Agents = (*ServerAgentsAPI)(&r.common) + r.Catalog = (*ServerCatalogAPI)(&r.common) + r.Commands = (*ServerCommandsAPI)(&r.common) + r.Connectors = (*ServerConnectorsAPI)(&r.common) + r.Environments = (*ServerEnvironmentsAPI)(&r.common) + r.Extensions = (*ServerExtensionsAPI)(&r.common) + r.Hooks = (*ServerHooksAPI)(&r.common) + r.Host = (*ServerHostAPI)(&r.common) + r.Instructions = (*ServerInstructionsAPI)(&r.common) + r.LlmInference = (*ServerLlmInferenceAPI)(&r.common) + r.ManagedSettings = (*ServerManagedSettingsAPI)(&r.common) + r.MCP = (*ServerMCPAPI)(&r.common) + r.Models = (*ServerModelsAPI)(&r.common) + r.Plugins = (*ServerPluginsAPI)(&r.common) + r.Runtime = (*ServerRuntimeAPI)(&r.common) + r.Sandbox = (*ServerSandboxAPI)(&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 { + client *jsonrpc2.Client +} + +// Experimental: InternalServerAccountAPI contains experimental APIs that may change or be +// removed. +type InternalServerAccountAPI internalServerAPI + +// DescribeAuthInfo renders the sign-in banner and the one-line account description the +// runtime uses for an authentication identity. The runtime words these in several places +// for its own callers, so a host that announces a sign-in or an account switch should +// render them from here rather than composing its own, which would let the two spellings +// drift apart. +// +// RPC method: account.describeAuthInfo. +// +// Parameters: The authentication identity whose shared wording should be rendered. +// +// Returns: The wording the runtime uses for an authentication identity. +// Internal: DescribeAuthInfo is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAccountAPI) DescribeAuthInfo(ctx context.Context, params *AccountDescribeAuthInfoRequest) (*AccountDescribeAuthInfoResult, error) { + raw, err := a.client.Request(ctx, "account.describeAuthInfo", params) + if err != nil { + return nil, err + } + var result AccountDescribeAuthInfoResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetGistSupport reports whether the supplied identity can create gists. Gists are +// unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed +// Users on github.com, so a host that offers gist actions should hide or disable them when +// this reports no support. +// +// RPC method: account.getGistSupport. +// +// Parameters: The authentication identity whose gist support should be reported. +// +// Returns: Whether the identity can create gists, and why not when it cannot. +// Internal: GetGistSupport is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAccountAPI) GetGistSupport(ctx context.Context, params *AccountGetGistSupportRequest) (*AccountGetGistSupportResult, error) { + raw, err := a.client.Request(ctx, "account.getGistSupport", params) + if err != nil { + return nil, err + } + var result AccountGetGistSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetTokenEnvVar names the environment variable supplying a classic personal access token, +// if one is set. A classic token cannot be upgraded in place, so a host that finds one +// should tell the user which variable to unset rather than starting an interactive sign-in +// that the variable would override. +// +// RPC method: account.getTokenEnvVar. +// +// Returns: The environment variable supplying a classic personal access token, when one is +// set. +// Internal: GetTokenEnvVar is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAccountAPI) GetTokenEnvVar(ctx context.Context) (*AccountGetTokenEnvVarResult, error) { + raw, err := a.client.Request(ctx, "account.getTokenEnvVar", nil) + if err != nil { + return nil, err + } + var result AccountGetTokenEnvVarResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetWebUrl resolves a path on the identity's GitHub host into an absolute URL, so a host +// can link to settings or documentation on the enterprise instance the user is signed in to +// rather than to github.com. Falls back to the public host when no identity is supplied. +// +// RPC method: account.getWebUrl. +// +// Parameters: A path to resolve against the GitHub host an identity is signed in to. +// +// Returns: An absolute URL on the identity's GitHub host. +// Internal: GetWebUrl is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerAccountAPI) GetWebUrl(ctx context.Context, params *AccountGetWebURLRequest) (*AccountGetWebURLResult, error) { + raw, err := a.client.Request(ctx, "account.getWebUrl", params) + if err != nil { + return nil, err + } + var result AccountGetWebURLResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerAgentsAPI contains experimental APIs that may change or be +// removed. +type InternalServerAgentsAPI internalServerAPI + +// CustomAgentInitialModelDecision resolves the model a custom agent asks for against the +// models actually available, and answers both the model to switch to and the warning a user +// should see when the agent's preference cannot be met. A custom agent may name several +// acceptable models in preference order, so the decision is a match rather than a lookup, +// and an agent whose preference is unavailable is a normal outcome that produces a warning +// rather than an error. A host must call this rather than pick the first available name +// itself, because the preference order and the wording of the warning are what keep one +// installation's agent selection the same as another's. +// +// RPC method: agents.customAgentInitialModelDecision. +// +// Parameters: The models a custom agent asks for, and the models actually available. +// +// Returns: The model to switch to, and the warning to show when the agent's preference +// could not be met. +// Internal: CustomAgentInitialModelDecision is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerAgentsAPI) CustomAgentInitialModelDecision(ctx context.Context, params *AgentsCustomAgentInitialModelDecisionParams) (*AgentsCustomAgentInitialModelDecisionResult, error) { + raw, err := a.client.Request(ctx, "agents.customAgentInitialModelDecision", params) + if err != nil { + return nil, err + } + var result AgentsCustomAgentInitialModelDecisionResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetAvailableBuiltins lists the shipped agents a client should offer right now, filtered +// by the feature flags it passes. `getBuiltins` names every agent the runtime knows about; +// some of those are gated, so a client rendering a picker wants this narrower list together +// with the description to show beside each name. +// +// RPC method: agents.getAvailableBuiltins. +// +// Parameters: The feature flags to evaluate shipped agents against. +// +// Returns: The shipped agents available under the requested flags. +// Internal: GetAvailableBuiltins is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAgentsAPI) GetAvailableBuiltins(ctx context.Context, params *AgentsGetAvailableBuiltinsRequest) (*AgentsGetAvailableBuiltinsResult, error) { + raw, err := a.client.Request(ctx, "agents.getAvailableBuiltins", params) + if err != nil { + return nil, err + } + var result AgentsGetAvailableBuiltinsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetBuiltinDefinition loads one shipped agent's YAML definition, for a client that needs +// what the agent declares rather than only its name. `getBuiltins` reports which names have +// a definition to load: a name outside its `yamlBasedNames` is special-cased in code and +// has none. The definition crosses as its own JSON rather than as contract-typed fields, +// because the runtime parses it with the agent schema's tolerant shape and re-typing it +// here would drop the keys that shape accepts and this one does not. The projected +// `__nativeCustomAgent` view the runtime derives is included, so a caller reading the +// declared model and a caller rendering the agent see the same definition. +// +// RPC method: agents.getBuiltinDefinition. +// +// Parameters: The shipped agent whose definition to load. +// +// Returns: One shipped agent's definition. +// Internal: GetBuiltinDefinition is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAgentsAPI) GetBuiltinDefinition(ctx context.Context, params *AgentsGetBuiltinDefinitionRequest) (*AgentsGetBuiltinDefinitionResult, error) { + raw, err := a.client.Request(ctx, "agents.getBuiltinDefinition", params) + if err != nil { + return nil, err + } + var result AgentsGetBuiltinDefinitionResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetBuiltinListingDefinition projects one shipped agent the way a picker lists it, reading +// only the metadata at the head of the definition file and stopping before the prompt body. +// `getBuiltinDefinition` answers the whole definition instead, so a client listing every +// shipped agent should prefer this one: the cost of a listing grows with the number of +// agents, and the prompt body is the part a listing never shows. The two also differ in +// shape. This returns the projected custom agent on its own, whereas `getBuiltinDefinition` +// returns the authored definition with that projection nested under `__nativeCustomAgent`. +// +// RPC method: agents.getBuiltinListingDefinition. +// +// Parameters: The shipped agent whose listing entry to load. +// +// Returns: One shipped agent, projected for a listing. +// Internal: GetBuiltinListingDefinition is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerAgentsAPI) GetBuiltinListingDefinition(ctx context.Context, params *AgentsGetBuiltinListingDefinitionRequest) (*AgentsGetBuiltinListingDefinitionResult, error) { + raw, err := a.client.Request(ctx, "agents.getBuiltinListingDefinition", params) + if err != nil { + return nil, err + } + var result AgentsGetBuiltinListingDefinitionResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetBuiltins lists the agents this runtime ships, by name. A consumer separating shipped +// agents from ones the user or a plugin authored should compare against these names rather +// than against `AgentInfo.source`: an authored agent may carry the `builtin` source while +// not being one of these, and the runtime treats the two as separate questions. +// `disableableNames` is the subset a user may turn off, which a client needs to decide +// whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML +// definition, which a client needs before asking the runtime to load one. +// +// RPC method: agents.getBuiltins. +// +// Returns: The agents this runtime ships, named so a consumer can tell them apart from +// authored ones. +// Internal: GetBuiltins is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerAgentsAPI) GetBuiltins(ctx context.Context) (*AgentsGetBuiltinsResult, error) { + raw, err := a.client.Request(ctx, "agents.getBuiltins", nil) + if err != nil { + return nil, err + } + var result AgentsGetBuiltinsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerFeatureFlagsAPI contains experimental APIs that may change or +// be removed. +type InternalServerFeatureFlagsAPI internalServerAPI + +// ListMetadata lists every feature flag this runtime declares, with the population each one +// is declared for, its experimental description, and the online-experiment flag it maps to. +// This is the static catalog: it describes how each flag is defined, not whether it is on +// for anyone. Use `featureFlags.resolve` for static values with caller overrides, not +// active runtime values or experiment assignments. +// +// RPC method: featureFlags.listMetadata. +// +// Returns: Every feature flag this runtime declares, with the shape each one was declared +// with. +// Internal: ListMetadata is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerFeatureFlagsAPI) ListMetadata(ctx context.Context) (*FeatureFlagsMetadataResult, error) { + raw, err := a.client.Request(ctx, "featureFlags.listMetadata", nil) + if err != nil { + return nil, err + } + var result FeatureFlagsMetadataResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Resolve computes static feature flags from the supplied population and overrides without +// changing runtime state or verifying audience membership. Starts from declared +// availability, then applies direct feature-flag environment values, user settings, and +// explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, +// authenticated startup gates, or active runtime state. Settings include +// `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience +// settings. Supply `baseFlags` to use an existing flag set instead of declared +// availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never +// recorded: a legacy staff account then counts as both populations. +// +// RPC method: featureFlags.resolve. +// +// Parameters: Caller population and overrides for static feature-flag resolution, +// independent of experiment assignments and active runtime state. +// +// Returns: The resolved feature flags, keyed by flag name. +// Internal: Resolve is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerFeatureFlagsAPI) Resolve(ctx context.Context, params *FeatureFlagsResolveRequest) (*FeatureFlagsResolveResult, error) { + raw, err := a.client.Request(ctx, "featureFlags.resolve", params) + if err != nil { + return nil, err + } + var result FeatureFlagsResolveResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveStartupGates resolves named gates against this installation's cached +// online-experiment assignment, for the account the runtime is already authenticated as. +// Unlike `featureFlags.resolve`, which layers static availability with the populations +// supplied, this reads the experiment assignment the runtime cached for its own current +// authentication, so a launch can honor a rollout before any session exists. The account is +// never taken from the request: naming one would read another account's cached assignments. +// The cached assignment answers immediately and any network refresh happens behind it, so +// this call does not wait on the network. Not available to an extension, which cannot carry +// the user's consent to read their assignment. +// +// RPC method: featureFlags.resolveStartupGates. +// +// Parameters: Caller population and startup inputs to resolve named online-experiment gates +// for. Carries no account: the runtime resolves the assignment for the authentication it +// already holds. +// +// Returns: The resolved gates, keyed by flag name. +// Internal: ResolveStartupGates is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerFeatureFlagsAPI) ResolveStartupGates(ctx context.Context, params *FeatureFlagsResolveStartupGatesRequest) (*FeatureFlagsResolveStartupGatesResult, error) { + raw, err := a.client.Request(ctx, "featureFlags.resolveStartupGates", params) + if err != nil { + return nil, err + } + var result FeatureFlagsResolveStartupGatesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerGitAPI contains experimental APIs that may change or be +// removed. +type InternalServerGitAPI internalServerAPI + +// CurrentBranchRemote reads the remote that the branch checked out in a working tree +// tracks, as `branch..remote` configures it. Reports `origin` rather than failing +// whenever there is no tracking configuration to read — on a detached HEAD, on a branch +// with no upstream, or when git itself fails — because a caller asking which remote to talk +// to needs an answer it can act on, not an error. Marked internal because it exists to +// carry a CLI call site off the napi boundary onto the SDK contract; it is migration +// plumbing, not a surface consumers are meant to depend on. +// +// RPC method: git.currentBranchRemote. +// +// Parameters: Working-tree path a git query applies to. +// +// Returns: The remote the checked-out branch tracks. +// Internal: CurrentBranchRemote is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerGitAPI) CurrentBranchRemote(ctx context.Context, params *GitCwdRequest) (*GitCurrentBranchRemoteResult, error) { + raw, err := a.client.Request(ctx, "git.currentBranchRemote", params) + if err != nil { + return nil, err + } + var result GitCurrentBranchRemoteResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ReposFromRemotes lists the GitHub repositories a working tree's remotes point at, one +// entry per distinct repository, so a caller can resolve a base and head repository without +// parsing remote URLs itself. When several remotes name the same repository, only the first +// is listed, and the entry keeps that remote name. Remotes pointing at no GitHub host are +// left out, so an empty list means the tree reaches GitHub through no remote. Failing to +// read the remotes is reported as an error rather than as an empty list, because the two +// mean different things to a caller. Marked internal because it exists to carry a CLI call +// site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface +// consumers are meant to depend on. +// +// RPC method: git.reposFromRemotes. +// +// Parameters: Git working tree whose GitHub remotes should be listed. +// +// Returns: The GitHub repositories a working tree's remotes point at. +// Internal: ReposFromRemotes is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerGitAPI) ReposFromRemotes(ctx context.Context, params *GitReposFromRemotesRequest) (*GitReposFromRemotesResult, error) { + raw, err := a.client.Request(ctx, "git.reposFromRemotes", params) + if err != nil { + return nil, err + } + var result GitReposFromRemotesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WorkingDirectoryContext collects the repository context of a working directory in one +// call: working tree root, repository identifier and host, current branch, and the HEAD and +// base commits. Every repository field is omitted when the path is not inside a git working +// tree, and the requested path is echoed back as `cwd`. The answer is the same +// `SessionWorkingDirectoryContext` that `session.metadata.recordContextChange` accepts, so +// a caller polling for a context change can forward the result unchanged. Marked internal +// because it exists to carry a CLI call site off the napi boundary onto the SDK contract; +// it is migration plumbing, not a surface consumers are meant to depend on. It can become +// public once an SDK consumer needs to derive session context from a directory itself. +// +// RPC method: git.workingDirectoryContext. +// +// Parameters: Working-tree path a git query applies to. +// +// Returns: Updated working directory and git context. Emitted as the new payload of +// `session.context_changed`. +// Internal: WorkingDirectoryContext is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerGitAPI) WorkingDirectoryContext(ctx context.Context, params *GitCwdRequest) (*SessionWorkingDirectoryContext, error) { + raw, err := a.client.Request(ctx, "git.workingDirectoryContext", params) + if err != nil { + return nil, err + } + var result SessionWorkingDirectoryContext + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerGitHubOwnersAPI contains experimental APIs that may change or +// be removed. +type InternalServerGitHubOwnersAPI internalServerAPI + +// Cancel abandons an owner listing started with the given request id. Answers `canceled: +// true` while a listing with that id is running. Answers `canceled: false` when the id was +// never registered, was registered but not used, was released after being abandoned, or its +// listing has ended. Canceling an unused id releases it, and a later `list` with that id is +// refused. The cancel acts only on owner listings and never reaches another request of the +// host. +// +// RPC method: gitHubOwners.cancel. +// +// Parameters: The owner listing to abandon. +// +// Returns: Whether the id named a running owner listing. +// Internal: Cancel is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerGitHubOwnersAPI) Cancel(ctx context.Context, params *GitHubOwnersCancelRequest) (*GitHubOwnersCancelResult, error) { + raw, err := a.client.Request(ctx, "gitHubOwners.cancel", params) + if err != nil { + return nil, err + } + var result GitHubOwnersCancelResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Lists the logins the authenticated user may act as — their own account first, then the +// organizations they belong to — by asking the GitHub API under the supplied credential. No +// credential travels in the request: `authInfo` selects one the runtime already holds, and +// the runtime resolves the token and the GitHub host from it. A failure the caller should +// render arrives as `message`; one it should raise arrives as `throwError`. +// +// RPC method: gitHubOwners.list. +// +// Parameters: Credential to list owners under, and the request id that makes the listing +// cancellable. +// +// Returns: Outcome of an owner listing. Exactly one of `owners` and `message` is present, +// except that `throwError` reports a failure the caller is expected to raise rather than +// render. +// Internal: List is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerGitHubOwnersAPI) List(ctx context.Context, params *GitHubOwnersListRequest) (*GitHubOwnersListResult, error) { + raw, err := a.client.Request(ctx, "gitHubOwners.list", params) + if err != nil { + return nil, err + } + var result GitHubOwnersListResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// NextRequestId registers a cancellable owner listing and returns its request id. Separate +// from `gitHubOwners.list` so the id exists before the listing starts: a caller that +// abandons the listing the moment it begins would otherwise have nothing to name in +// `gitHubOwners.cancel`. The id serves one listing only. Long-abandoned unused ids can be +// released by later allocations. +// +// RPC method: gitHubOwners.nextRequestId. +// +// Returns: A freshly registered request id. Registering it before the listing starts is +// what lets a cancel that races the request still find the owner listing slot. The id +// serves one listing only. Long-abandoned unused ids can be released by later allocations. +// Internal: NextRequestId is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerGitHubOwnersAPI) NextRequestId(ctx context.Context) (*GitHubOwnersRequestIDResult, error) { + raw, err := a.client.Request(ctx, "gitHubOwners.nextRequestId", nil) + if err != nil { + return nil, err + } + var result GitHubOwnersRequestIDResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerGitHubRepositoryAPI contains experimental APIs that may +// change or be removed. +type InternalServerGitHubRepositoryAPI internalServerAPI + +// AtPath resolves the GitHub repository that owns a working-tree path by reading the +// selected git remote configured for it, preferring `origin`. Returns a null `repository` +// when the path is inside a git working tree but that selected remote does not resolve to a +// GitHub host. Fails when the path is not inside a git working tree at all, so a caller can +// tell 'not a repository' apart from 'a repository with no GitHub remote'. +// +// RPC method: gitHubRepository.atPath. +// +// Parameters: Working-tree path whose owning GitHub repository should be resolved. +// +// Returns: The GitHub repository that owns the requested path, when the selected remote +// (`origin`, else the first) is on a GitHub host. +// Internal: AtPath is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerGitHubRepositoryAPI) AtPath(ctx context.Context, params *GitHubRepositoryAtPathRequest) (*GitHubRepositoryAtPathResult, error) { + raw, err := a.client.Request(ctx, "gitHubRepository.atPath", params) + if err != nil { + return nil, err + } + var result GitHubRepositoryAtPathResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerGlobalStateAPI contains experimental APIs that may change or +// be removed. +type InternalServerGlobalStateAPI internalServerAPI + +// Load reads the host's machine-wide state: which plugins are installed and the one-off +// flags and timestamps that record what the user has already been shown or migrated. This +// is the state that outlives a single session and a single workspace, so a host reads it to +// decide whether to run a first-launch step, offer an onboarding prompt, or skip one it has +// already completed. The stored credentials are deliberately not part of this result; a +// caller that needs an authenticated identity asks the account methods for it instead. +// Reading is non-destructive and every field is optional, because a fresh install has +// recorded nothing yet. +// +// RPC method: globalState.load. +// +// Returns: The host's machine-wide state. Every field is optional because a fresh install +// has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a +// negative answer. Stored credentials are deliberately absent from this shape. +// Internal: Load is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerGlobalStateAPI) Load(ctx context.Context) (*GlobalStateLoadResult, error) { + raw, err := a.client.Request(ctx, "globalState.load", nil) + if err != nil { + return nil, err + } + var result GlobalStateLoadResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// LoadForConfigDir reads the host's machine-wide state exactly as `globalState.load` does, +// but from a caller-supplied configuration directory instead of the one the server resolved +// for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's +// per-session `configDir` override — so the state read matches the directory that session +// actually uses. An absent or empty `configDir` resolves the server's own home, making this +// identical to `globalState.load`. The stored credentials are omitted here for the same +// reason they are omitted from `globalState.load`: a caller that needs an authenticated +// identity asks the account methods instead, so pointing this at another directory cannot +// be used to read the credentials kept in it. +// +// RPC method: globalState.loadForConfigDir. +// +// Parameters: Selects the configuration directory whose machine-wide state to read. +// +// Returns: The host's machine-wide state. Every field is optional because a fresh install +// has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a +// negative answer. Stored credentials are deliberately absent from this shape. +// Internal: LoadForConfigDir is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerGlobalStateAPI) LoadForConfigDir(ctx context.Context, params *GlobalStateLoadForConfigDirRequest) (*GlobalStateLoadResult, error) { + raw, err := a.client.Request(ctx, "globalState.loadForConfigDir", params) + if err != nil { + return nil, err + } + var result GlobalStateLoadResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteKey records one top-level key in the host's machine-wide state, the counterpart to +// `globalState.load`. A host calls this to remember that it has shown an onboarding step, +// asked a one-off question, or completed a migration, so the next run can skip it. Only the +// named key is replaced and the rest of the document is preserved, which lets two writers +// record different flags without overwriting each other; passing no value removes the key +// instead. Only the keys a host records itself are writable: `appTipShown`, +// `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, +// `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is +// refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the +// staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which +// apply repository and managed-policy checks. +// +// RPC method: globalState.writeKey. +// +// Parameters: A single top-level key to record in the host's machine-wide state. The write +// replaces only that key and leaves the rest of the document untouched, so two writers +// recording different one-off flags do not overwrite each other. The stored credential keys +// cannot be written through this method. +// Internal: WriteKey is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerGlobalStateAPI) WriteKey(ctx context.Context, params *GlobalStateWriteKeyRequest) (*GlobalStateWriteKeyResult, error) { + raw, err := a.client.Request(ctx, "globalState.writeKey", params) + if err != nil { + return nil, err + } + var result GlobalStateWriteKeyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerHostAPI contains experimental APIs that may change or be +// removed. +type InternalServerHostAPI internalServerAPI + +// CreateSession requests app-owned materialization over the owning SDK participant. +// +// RPC method: host.createSession. +// +// Parameters: One application-owned session handoff, requested by the supervised hosting +// participant. +// +// Returns: The resident session the application has materialized on its own connection. +// Internal: CreateSession is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerHostAPI) CreateSession(ctx context.Context, params *HostSessionCreateRequest) (*HostCreateSessionResult, error) { + raw, err := a.client.Request(ctx, "host.createSession", params) + if err != nil { + return nil, err + } + var result HostCreateSessionResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetConfiguration returns listener settings only to the supervised hosting participant +// over its SDK connection. +// +// RPC method: host.getConfiguration. +// +// Returns: Normalized listener settings delivered only to the supervised hosting +// participant. +// Internal: GetConfiguration is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerHostAPI) GetConfiguration(ctx context.Context) (*HostGetConfigurationResult, error) { + raw, err := a.client.Request(ctx, "host.getConfiguration", nil) + if err != nil { + return nil, err + } + var result HostGetConfigurationResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetEnvironmentCredentials resolves current authenticated credentials and remote-control +// policy only for the runtime-owned Mission Control hosting participant. +// +// RPC method: host.getEnvironmentCredentials. +// +// Returns: Private credentials delivered only to a runtime-owned Mission Control hosting +// participant. +// Internal: GetEnvironmentCredentials is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerHostAPI) GetEnvironmentCredentials(ctx context.Context) (*HostGetEnvironmentCredentialsResult, error) { + raw, err := a.client.Request(ctx, "host.getEnvironmentCredentials", nil) + if err != nil { + return nil, err + } + var result HostGetEnvironmentCredentialsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Ready reports a supervised hosting participant's bound AHP endpoint after its SDK +// handshake. +// +// RPC method: host.ready. +// +// Parameters: Readiness reported by the supervised hosting participant on its own SDK +// connection. +// +// Returns: Empty acknowledgement for a completed host lifecycle operation. +// Internal: Ready is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerHostAPI) Ready(ctx context.Context, params *HostReadyRequest) (*HostReadyResult, error) { + raw, err := a.client.Request(ctx, "host.ready", params) + if err != nil { + return nil, err + } + var result HostReadyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ReleaseSession releases app ownership retention after AHP detaches. +// +// RPC method: host.releaseSession. +// +// Parameters: Ends one participation, not the application's session lifetime. +// +// Returns: Empty acknowledgement for a completed host lifecycle operation. +// Internal: ReleaseSession is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerHostAPI) ReleaseSession(ctx context.Context, params *HostSessionReleaseRequest) (*HostReleaseSessionResult, error) { + raw, err := a.client.Request(ctx, "host.releaseSession", params) + if err != nil { + return nil, err + } + var result HostReleaseSessionResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerInstructionsAPI contains experimental APIs that may change or +// be removed. +type InternalServerInstructionsAPI internalServerAPI + +// ClearCache drops the runtime's in-memory cache of discovered custom instructions so the +// next discovery reads them from disk again. A host calls this after it changes instruction +// files, or after it trusts a folder whose instructions an earlier discovery skipped, so +// that a session started afterwards sees the current files instead of a cached earlier +// answer. The call performs no I/O of its own and removes nothing from disk; it only +// invalidates, so the cost lands on the next discovery. Returns once the cache is +// clear, which is what lets a caller order a session start after it. Marked internal +// because it exists to carry a CLI call site off the napi boundary onto the SDK contract; +// it is migration plumbing, not a surface consumers are meant to depend on. +// +// RPC method: instructions.clearCache. +// Internal: ClearCache is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerInstructionsAPI) ClearCache(ctx context.Context) (*InstructionsClearCacheResult, error) { + raw, err := a.client.Request(ctx, "instructions.clearCache", nil) + if err != nil { + return nil, err + } + var result InstructionsClearCacheResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// DiscoverRepoSources discovers the instruction sources for one caller-named location and +// returns them in the order the runtime applies them. `discover` answers for a set of +// project paths and derives the rest of its scope itself; this one instead takes every +// argument from the caller — the extra directories to scan and whether to descend into +// nested instruction files — and honors them as given. It also includes instruction +// directories from trusted repository settings, matching native repository discovery. Use +// it when the caller knows its own scope and no session exists to derive that scope from, +// such as a host reporting how many instruction files a directory contributes before any +// session starts. Marked internal because it exists to carry a CLI call site off the napi +// boundary onto the SDK contract; it is migration plumbing, not a surface consumers are +// meant to depend on. +// +// RPC method: instructions.discoverRepoSources. +// +// Parameters: Explicit discovery arguments for one location, supplied by the caller rather +// than derived from a session. +// +// Returns: Instruction sources discovered across user, repository, and plugin sources. +// Internal: DiscoverRepoSources is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerInstructionsAPI) DiscoverRepoSources(ctx context.Context, params *InstructionsDiscoverRepoSourcesRequest) (*ServerInstructionSourceList, error) { + raw, err := a.client.Request(ctx, "instructions.discoverRepoSources", params) + if err != nil { + return nil, err + } + var result ServerInstructionSourceList + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetInitPrompt returns the prompt the `init` command runs to author repository +// instructions. A host offering its own initialize action sends this text so the +// instructions it produces match the ones the CLI produces. The text is fixed for a build +// and depends on no configuration, session or repository. +// +// RPC method: instructions.getInitPrompt. +// +// Returns: The prompt the init command runs. +// Internal: GetInitPrompt is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerInstructionsAPI) GetInitPrompt(ctx context.Context) (*InstructionsInitPromptResult, error) { + raw, err := a.client.Request(ctx, "instructions.getInitPrompt", nil) + if err != nil { + return nil, err + } + var result InstructionsInitPromptResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerManagedSettingsAPI contains experimental APIs that may change +// or be removed. +type InternalServerManagedSettingsAPI internalServerAPI + +// ApplyControls stamps an effective managed policy's individually-controlled entries onto a +// user settings document, returning the settings a host should actually act on. The managed +// layer wins on every plugin spec and marketplace name it names, and leaves everything it +// does not name as the user wrote it. Hosts use this rather than merging the two documents +// themselves, because the merge is per entry rather than per document and a whole-document +// overlay would either discard the user's unmanaged entries or let a user entry outrank a +// managed one. Omitting the managed layer returns the settings unchanged, which is what an +// unmanaged host wants. Rejects when either document is present but is not a JSON object +// rather than treating it as absent, since silently dropping a malformed policy hands the +// user's layer the win on exactly the entries the policy exists to control. +// +// RPC method: managedSettings.applyControls. +// +// Parameters: A user settings document and the effective managed policy whose controlled +// entries should be stamped onto it. +// +// Returns: The user settings with the managed layer's controlled entries stamped on. +// Internal: ApplyControls is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) ApplyControls(ctx context.Context, params *ManagedSettingsApplyControlsParams) (*ManagedSettingsApplyControlsResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.applyControls", params) + if err != nil { + return nil, err + } + var result ManagedSettingsApplyControlsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Ingest resolves managed (enterprise policy) settings for a host from every layer at once: +// the account's server-delivered policy, the device/MDM layer, and a platform policy +// helper. Hosts use this instead of fetching and composing the layers themselves, because +// the per-layer precedence and the fail-closed rules that apply when a layer cannot be +// confirmed are the runtime's own and must match the policy a session will later enforce. +// It does not retain or apply anything to process-global policy state, so a host may call +// it before any session exists — which is the point, since plugin activation and one-shot +// commands resolve policy before a session is available to carry it. The returned per-layer +// outcome flags are load-bearing rather than diagnostic: a host must distinguish an +// unmanaged device from a managed device whose policy could not be confirmed, and apply its +// fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather +// than logging them, so a host that runs before a log sink exists still sees them. +// +// RPC method: managedSettings.ingest. +// +// Parameters: Inputs describing the host and account an ingestion should resolve managed +// policy for. +// +// Returns: The managed policy layers an ingestion resolved, together with the per-layer +// outcome flags a host needs to decide how much to trust the result. The flags are reported +// rather than folded into the settings because a host must be able to distinguish an +// unmanaged device from a managed device whose policy could not be confirmed, and apply its +// fail-closed gates in the second case. +// Internal: Ingest is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerManagedSettingsAPI) Ingest(ctx context.Context, params *ManagedSettingsIngestParams) (*ManagedSettingsIngestResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.ingest", params) + if err != nil { + return nil, err + } + var result ManagedSettingsIngestResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// LoadRemoteControl resolves the managed `remoteControl` policy for an account on its own, +// for a host deciding whether a remote-control session may start. Composes the same layers +// as `managedSettings.ingest` and returns only that one key, so a host does not have to +// know which layer won. An absent policy means the account is unmanaged for this capability +// and the host may proceed; that default is safe only while absence really does mean "no +// policy", so a service refusal that says an account policy exists which this client is too +// old to enforce resolves to an explicit disabled policy instead of to absence. A +// resolution that cannot be completed is rejected rather than answered as absence, for the +// same reason. +// +// RPC method: managedSettings.loadRemoteControl. +// +// Parameters: Inputs describing the host and account whose managed remote-control policy +// should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no +// retention decision: reading this gate never becomes this runtime process's startup policy. +// +// Returns: The managed remote-control policy in force for an account, if any. An absent +// policy means the account is unmanaged for this capability, which a host reads as allowed +// — so absence here is a positive statement that no policy applies, never a stand-in for a +// resolution that failed. A resolution that cannot be completed is rejected instead. +// Internal: LoadRemoteControl is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) LoadRemoteControl(ctx context.Context, params *ManagedSettingsLoadRemoteControlParams) (*ManagedSettingsLoadRemoteControlResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.loadRemoteControl", params) + if err != nil { + return nil, err + } + var result ManagedSettingsLoadRemoteControlResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ParseClientValue validates the managed settings a client is supplying for a session it is +// about to open, and returns them reduced to the keys a client is allowed to set. A +// client-supplied policy is not the same thing as an administrator's: it may only narrow +// permissions, so this accepts `permissions` and rejects every other key outright rather +// than ignoring it. Rejecting is the point — a host that silently dropped an unsupported +// key would report a policy as applied while running without it. Hosts call this before +// opening the session rather than letting the open fail, so a malformed policy is reported +// against the request that carried it. The runtime applies the same rule again when the +// session starts, so this cannot be used to smuggle a wider document past it. An accepted +// document that sets nothing comes back as an empty object, which is distinct from +// supplying nothing at all. +// +// RPC method: managedSettings.parseClientValue. +// +// Parameters: The client-supplied managed settings to validate and normalize. Omitting them +// is valid and yields no policy. +// +// Returns: The accepted managed settings, reduced to the keys a client is allowed to set. +// Internal: ParseClientValue is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) ParseClientValue(ctx context.Context, params *ManagedSettingsParseClientValueParams) (*ManagedSettingsParseClientValueResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.parseClientValue", params) + if err != nil { + return nil, err + } + var result ManagedSettingsParseClientValueResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ReadDevice discovers device-managed settings the way the runtime's own device layer does, +// and reports the sandbox floor and the load outcome alongside the validated document. This +// differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a +// document that validates to an empty object is reported as absent rather than as an empty +// policy, a discovery error does not suppress a document that still validates, and a +// failure is reported as a flag rather than only as error text. Hosts that compose the +// device layer into an effective policy use this, because `managedSettings.read` cannot +// distinguish "no device policy" from "device policy could not be read" and would silently +// hand the user's own layer the win. +// +// RPC method: managedSettings.readDevice. +// +// Returns: The device-managed settings layer, with the sandbox floor and the load outcome a +// host needs to compose it into an effective policy. +// Internal: ReadDevice is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerManagedSettingsAPI) ReadDevice(ctx context.Context) (*ManagedSettingsReadDeviceResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.readDevice", nil) + if err != nil { + return nil, err + } + var result ManagedSettingsReadDeviceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveBypassDisableTransition decides what a host must do to its bypass-permissions +// state after a managed-policy resolution lands, given the state already in force and the +// account now signed in. A host holds two pieces of state — which layer disabled bypass +// mode, and for a server-delivered disable, the account it was pinned to — and cannot +// decide the next step from the new policy alone. Three rules make that so, and each one is +// a control rather than a preference. A device/MDM disable outranks the account, so a later +// server answer never lifts it. An unknown policy, which is what a failed fetch or a +// refusal this build cannot enforce yields, preserves whatever is in force instead of +// reverting to permissive. And a server disable is lifted only when the account it was +// pinned to is no longer the signed-in one, which is what makes signing in to an +// unrestricted account recover without a restart while a reconnect on the same restricted +// account does not. Hosts call this rather than reimplementing it because getting the +// pinning backwards either strands a disable on an account that never carried one or drops +// one that still applies. `setDisabledState` is omitted when the host must leave its stored +// flag untouched, which is distinct from being told to set it to false. +// +// RPC method: managedSettings.resolveBypassDisableTransition. +// +// Parameters: The bypass-permissions state a host holds today, the account now signed in, +// and what the managed-policy resolution said. +// +// Returns: The bypass-permissions state a host should hold after the resolution, and what +// it must do to get there. +// Internal: ResolveBypassDisableTransition is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveBypassDisableTransition(ctx context.Context, params *ManagedSettingsResolveBypassDisableTransitionParams) (*ManagedSettingsResolveBypassDisableTransitionResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveBypassDisableTransition", params) + if err != nil { + return nil, err + } + var result ManagedSettingsResolveBypassDisableTransitionResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveDeviceForceLoginOrgsGate evaluates the device-channel enterprise sign-in pin (MDM +// plist, registry, or managed-settings file) against a credential, without resolving any +// server-delivered policy. This is the gate an entry point runs before it branches, and the +// only one that can refuse a developer's first sign-in: it is local, needs no credential, +// and a server-delivered pin only ever reaches accounts already inside the organization. It +// fails closed by construction — a discovery that cannot determine whether a pin exists +// refuses rather than allows, because a control that fails open under a triggerable +// condition is not a control. Hosts that also want the server channel should call +// `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. +// +// RPC method: managedSettings.resolveDeviceForceLoginOrgsGate. +// +// Parameters: The credential and environment to evaluate the device-channel sign-in pin +// against. +// +// Returns: The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A +// managed device may pin Copilot to an approved set of GitHub organizations so a developer +// cannot sign in with a personal — or another enterprise's — account and escape every +// control that keys off the signed-in identity. A host must refuse to proceed when +// `allowed` is false; the remaining fields explain the refusal rather than qualifying it. +// Internal: ResolveDeviceForceLoginOrgsGate is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveDeviceForceLoginOrgsGate(ctx context.Context, params *ManagedSettingsResolveDeviceForceLoginOrgsGateParams) (*ForceLoginOrgsDecision, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveDeviceForceLoginOrgsGate", params) + if err != nil { + return nil, err + } + var result ForceLoginOrgsDecision + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveEffectiveValue composes the supplied server, device/MDM, device sandbox floor and +// policy-helper layers into the single effective managed policy a host should enforce, +// resolving each key across the layers by the runtime's own precedence rules. Hosts that +// assemble managed layers themselves use this so their precedence matches the runtime's +// exactly instead of reimplementing it. The composition is not a pure function of its +// inputs: an advisory sandbox force-on that arrived over the server channel is declined +// when this host cannot run a sandbox, so the result reflects the runtime host's +// capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when +// that happened. Enforced channels (device/MDM and policy helper) are never declined, and a +// server force-on carrying `failIfUnavailable` is preserved so the session fails loudly +// instead of quietly running unsandboxed. Rejects when a supplied layer is present but is +// not a JSON object, rather than treating it as unmanaged, because silently dropping a +// malformed policy would hand the user's own layer the win on exactly the keys the policy +// exists to control. +// +// RPC method: managedSettings.resolveEffectiveValue. +// +// Parameters: The managed-settings layers to compose into an effective policy. Every layer +// is optional; omitting all of them yields no effective policy. +// +// Returns: The effective managed policy composed from the supplied layers. +// Internal: ResolveEffectiveValue is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveEffectiveValue(ctx context.Context, params *ManagedSettingsResolveEffectiveValueParams) (*ManagedSettingsResolveEffectiveValueResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveEffectiveValue", params) + if err != nil { + return nil, err + } + var result ManagedSettingsResolveEffectiveValueResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveStartupPolicy resolves the managed (enterprise policy) settings a host must +// enforce from startup, and judges the account against the enterprise sign-in pin in the +// same pass. This composes the layers the way `managedSettings.ingest` does and then +// answers the two questions a host cannot answer for itself: which fail-closed floors apply +// when a layer could not be confirmed, and whether this credential is allowed to sign in at +// all. The sign-in verdict is the reason a host must not assemble this itself from +// `managedSettings.ingest` — a pinned organization is an access control, and a host that +// composed the layers but skipped the pin would let a developer sign in with a personal or +// another enterprise's account and escape every control that keys off the signed-in +// identity. The verdict is computed on every resolution, including one that is not +// retained, so declining to apply policy never widens access. Set `retainAndApply` to keep +// the resolved policy as this runtime process's startup policy; leave it false to resolve +// without side effects. +// +// RPC method: managedSettings.resolveStartupPolicy. +// +// Parameters: Inputs describing the host and account a startup policy resolution should run +// for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved +// policy is retained for this runtime process. +// +// Returns: The startup policy a resolution composed, the per-layer outcome flags a host +// needs to decide how much to trust it, and the enterprise sign-in verdict for the +// credential it ran against. The flags are reported rather than folded into the settings +// because a host must distinguish an unmanaged device from a managed device whose policy +// could not be confirmed, and apply its fail-closed gates in the second case. +// Internal: ResolveStartupPolicy is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveStartupPolicy(ctx context.Context, params *ManagedSettingsResolveStartupPolicyParams) (*ManagedSettingsResolveStartupPolicyResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveStartupPolicy", params) + if err != nil { + return nil, err + } + var result ManagedSettingsResolveStartupPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// RetainPolicy retains the supplied managed layers as this runtime process's startup policy +// and re-applies the result to every live session. Hosts that own their own short-lived +// process policy use this, so a guarded mutation is checked against the policy the host +// actually fetched. Retaining is a whole-process replacement rather than a merge, so a host +// that already resolved a good policy must not retain a partial one over it. The failure +// flags are honest inputs rather than assumptions: reporting a fetch or load that failed +// keeps the layers already retained, and the interim fail-closed state, instead of clearing +// them. +// +// RPC method: managedSettings.retainPolicy. +// +// Parameters: The managed layers to retain as this process's startup policy, with the +// outcome of fetching each one. +// Internal: RetainPolicy is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerManagedSettingsAPI) RetainPolicy(ctx context.Context, params *ManagedSettingsRetainPolicyParams) (*ManagedSettingsRetainPolicyResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.retainPolicy", params) + if err != nil { + return nil, err + } + var result ManagedSettingsRetainPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerMCPAPI contains experimental APIs that may change or be +// removed. +type InternalServerMCPAPI internalServerAPI + +// ListBuiltinServerNames lists the MCP servers the runtime supplies itself, so a host that +// disables the built-ins wholesale suppresses exactly the set the runtime would otherwise +// add. The names are fixed for a build and depend on no configuration, session or account. +// +// RPC method: mcp.listBuiltinServerNames. +// +// Returns: Names of the MCP servers the runtime supplies itself. +// Internal: ListBuiltinServerNames is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerMCPAPI) ListBuiltinServerNames(ctx context.Context) (*MCPListBuiltinServerNamesResult, error) { + raw, err := a.client.Request(ctx, "mcp.listBuiltinServerNames", nil) + if err != nil { + return nil, err + } + var result MCPListBuiltinServerNamesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ShouldExcludeGitHubTools reports whether the gh-replaceable GitHub MCP tools may be +// clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build +// option. The tools are redundant only when the session can reach a shell *and* the host +// has the `gh` that would replace them, so both halves are decided here. The shell half +// runs the platform shell tool through the runtime's own tool-filter matcher, so entry +// forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds +// its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters +// already rule the shell out. Host presence alone is not enough: a session restricted to, +// say, `view` would otherwise lose the built-in issue-read fallback while having no shell +// to replace it with. The answer describes the host the runtime runs on, so it is never +// forwarded to a remote engine. +// +// RPC method: mcp.shouldExcludeGitHubTools. +// +// Parameters: The session tool filters that decide whether the session still has a shell to +// run `gh` with. +// +// Returns: Whether the gh-replaceable GitHub MCP tools may be clipped for the session +// described by the request. +// Internal: ShouldExcludeGitHubTools is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerMCPAPI) ShouldExcludeGitHubTools(ctx context.Context, params *MCPShouldExcludeGitHubToolsRequest) (*MCPShouldExcludeGitHubToolsResult, error) { + raw, err := a.client.Request(ctx, "mcp.shouldExcludeGitHubTools", params) + if err != nil { + return nil, err + } + var result MCPShouldExcludeGitHubToolsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerMCPRegistryAPI contains experimental APIs that may change or +// be removed. +type InternalServerMCPRegistryAPI internalServerAPI + +// AllocateRequestId allocates an ID for one cancellable MCP registry search. The ID exists +// before the search starts, so callers can cancel before it starts. The networking stack +// supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At +// capacity, another allocation can reclaim an unused ID. Active searches retain their IDs +// until they finish. +// +// RPC method: mcp.registry.allocateRequestId. +// +// Returns: Request id naming a cancellable registry search. +// Internal: AllocateRequestId is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerMCPRegistryAPI) AllocateRequestId(ctx context.Context) (*MCPRegistryRequestIDResult, error) { + raw, err := a.client.Request(ctx, "mcp.registry.allocateRequestId", nil) + if err != nil { + return nil, err + } + var result MCPRegistryRequestIDResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Cancel abandons the registry search that uses the given request ID. It acts only on IDs +// from `mcp.registry.allocateRequestId`, so it never cancels another component's request. +// Answers `canceled: true` when it stops a running search. Answers `canceled: false` for +// unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It +// releases an unused reservation, so a later search with that ID is refused. +// +// RPC method: mcp.registry.cancel. +// +// Parameters: Registry search to abandon. +// +// Returns: Whether the cancel reached a live search. +// Internal: Cancel is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerMCPRegistryAPI) Cancel(ctx context.Context, params *MCPRegistryCancelRequest) (*MCPRegistryCancelResult, error) { + raw, err := a.client.Request(ctx, "mcp.registry.cancel", params) + if err != nil { + return nil, err + } + var result MCPRegistryCancelResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Searches the MCP registry the supplied credential may read, resolving the registry +// endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` +// identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities +// can use a token embedded in the request first. The runtime follows registry pages, keeps +// the newest entry per server name, cuts the list to `limit`, and sorts an empty-query +// result by GitHub stars. Each server object is carried opaquely. +// +// RPC method: mcp.registry.search. +// +// Parameters: Registry search terms, the credential to search under, and the request id +// that makes the search cancellable. +// +// Returns: Servers selected from the registry response. +// Internal: Search is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerMCPRegistryAPI) Search(ctx context.Context, params *MCPRegistrySearchRequest) (*MCPRegistrySearchResult, error) { + raw, err := a.client.Request(ctx, "mcp.registry.search", params) + if err != nil { + return nil, err + } + var result MCPRegistrySearchResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Registry returns experimental APIs that may change or be removed. +func (s *InternalServerMCPAPI) Registry() *InternalServerMCPRegistryAPI { + return (*InternalServerMCPRegistryAPI)(s) +} + +// Experimental: InternalServerPermissionsAPI contains experimental APIs that may change or +// be removed. +type InternalServerPermissionsAPI internalServerAPI + +// EvaluateManagedPolicy interprets a verbatim managed `permissions` slice into the three +// policy questions a host asks before granting elevated permissions: whether +// bypass-permissions mode is forbidden, whether a policy exists that this build could not +// determine, and whether the layer supplies permission rules the session must enforce. An +// absent or empty slice means no managed policy applies. The runtime and its permission +// service share one policy type, so a new managed permission setting is interpreted in +// exactly one place; a host that reimplements the reading would silently diverge the first +// time that set grows. Hosts must fail closed on an undetermined policy rather than +// treating it as permission granted. +// +// RPC method: permissions.evaluateManagedPolicy. +// +// Parameters: The verbatim managed `permissions` slice to interpret. +// +// Returns: The policy questions a host asks before granting elevated permissions. +// Internal: EvaluateManagedPolicy is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerPermissionsAPI) EvaluateManagedPolicy(ctx context.Context, params *PermissionsEvaluateManagedPolicyParams) (*PermissionsEvaluateManagedPolicyResult, error) { + raw, err := a.client.Request(ctx, "permissions.evaluateManagedPolicy", params) + if err != nil { + return nil, err + } + var result PermissionsEvaluateManagedPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerPermissionsFolderTrustAPI contains experimental APIs that may +// change or be removed. +type InternalServerPermissionsFolderTrustAPI internalServerAPI + +// CheckTrust reports whether a folder is trusted, reading the persisted trusted-folders +// list directly rather than through a session. Use this from a host that has no session +// yet, such as a one-shot command deciding whether to honor a checkout's own settings. It +// differs from the session-scoped check in two ways that matter: it takes the configuration +// directory to read the list from, instead of inheriting the session's, and it answers only +// from the persisted list, so trust a user granted for the lifetime of one session is not +// visible here. A host that has a session should prefer the session-scoped check, which +// also covers session-only trust. +// +// RPC method: permissions.folderTrust.checkTrust. +// +// Parameters: A folder to check against a persisted trusted-folders list, and the +// configuration directory holding that list. +// +// Returns: Folder trust check result. +// Internal: CheckTrust is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerPermissionsFolderTrustAPI) CheckTrust(ctx context.Context, params *FolderTrustIsTrustedParams) (*FolderTrustCheckResult, error) { + raw, err := a.client.Request(ctx, "permissions.folderTrust.checkTrust", params) + if err != nil { + return nil, err + } + var result FolderTrustCheckResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: FolderTrust returns experimental APIs that may change or be removed. +func (s *InternalServerPermissionsAPI) FolderTrust() *InternalServerPermissionsFolderTrustAPI { + return (*InternalServerPermissionsFolderTrustAPI)(s) +} + +// Experimental: InternalServerPermissionsLocationsAPI contains experimental APIs that may +// change or be removed. +type InternalServerPermissionsLocationsAPI internalServerAPI + +// CleanupOrphaned drops stored per-location permission grants whose directory no longer +// exists, and reports which location keys were removed. Runs against the permission store +// under the runtime's own Copilot home, the same store +// `session.permissions.locations.resolve` reads. Marked internal because it exists to carry +// a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, +// not a surface consumers are meant to depend on. It can become public once an SDK consumer +// needs to prune its own permission store. +// +// RPC method: permissions.locations.cleanupOrphaned. +// +// Returns: Which stored location permissions were dropped because their directory is gone. +// Internal: CleanupOrphaned is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerPermissionsLocationsAPI) CleanupOrphaned(ctx context.Context) (*LocationPermissionsCleanupResult, error) { + raw, err := a.client.Request(ctx, "permissions.locations.cleanupOrphaned", nil) + if err != nil { + return nil, err + } + var result LocationPermissionsCleanupResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Locations returns experimental APIs that may change or be removed. +func (s *InternalServerPermissionsAPI) Locations() *InternalServerPermissionsLocationsAPI { + return (*InternalServerPermissionsLocationsAPI)(s) +} + +// Experimental: InternalServerPersistenceAPI contains experimental APIs that may change or +// be removed. +type InternalServerPersistenceAPI internalServerAPI + +// WriteRawJsonLocked atomically replaces a JSON file's entire contents while holding the +// runtime's per-path lock. The lock lives in the runtime process, so a host that writes +// these files itself takes no part in it and can tear a concurrent runtime write; route the +// write here instead. Unlike a merging write this never reads or parses the existing file, +// so a previously corrupted snapshot is replaced wholesale rather than failing every later +// write. Use it only for callers that always persist a complete snapshot. +// +// RPC method: persistence.writeRawJsonLocked. +// +// Parameters: A complete JSON snapshot to write under the runtime's per-path file lock. +// +// Returns: The outcome of a locked snapshot write. +// Internal: WriteRawJsonLocked is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerPersistenceAPI) WriteRawJsonLocked(ctx context.Context, params *PersistenceWriteRawJSONLockedRequest) (*PersistenceWriteRawJSONLockedResult, error) { + raw, err := a.client.Request(ctx, "persistence.writeRawJsonLocked", params) + if err != nil { + return nil, err + } + var result PersistenceWriteRawJSONLockedResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerRepoAPI contains experimental APIs that may change or be +// removed. +type InternalServerRepoAPI internalServerAPI + +// Experimental: InternalServerRepoSettingsAPI contains experimental APIs that may change or +// be removed. +type InternalServerRepoSettingsAPI internalServerAPI + +// Edit atomically edits one allowed top-level repository setting. Reads the raw file, +// preserves unrelated keys, applies one scalar or list edit, validates the result and +// writes under one file lock, so concurrent sibling or list edits are not lost. A malformed +// or unsafe existing file returns `invalid` without a write; rejected keys, invalid values +// and I/O errors reject the call. +// +// RPC method: repo.settings.edit. +// +// Parameters: One atomic edit of an allowed top-level repository setting. +// +// Returns: Outcome of an atomic user or repository settings edit. +// Internal: Edit is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerRepoSettingsAPI) Edit(ctx context.Context, params *RepoSettingsEditRequest) (*SettingsEditResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.edit", params) + if err != nil { + return nil, err + } + var result SettingsEditResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ReadRaw reads one repository settings file without settings normalization or layering. +// The existing JSONC parser accepts comments and trailing commas and applies its +// prototype-safety rules. Missing or blank files return an empty valid config. Invalid +// files return an empty config with invalid=true; other read failures reject. +// +// RPC method: repo.settings.readRaw. +// +// Parameters: Which repository settings file to read. +// +// Returns: Parsed repository settings without normalization or layering. +// Internal: ReadRaw is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) ReadRaw(ctx context.Context, params *RepoSettingsReadRawRequest) (*RepoSettingsReadRawResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.readRaw", params) + if err != nil { + return nil, err + } + var result RepoSettingsReadRawResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteAll replaces the repository-overridable settings in one locked write. Allowed keys +// present in settings are validated and written; allowed keys absent from settings are +// removed. Other input keys are ignored, and unknown keys already stored in the file remain +// unchanged. Invalid values or an invalid existing file reject without a partial write. +// +// RPC method: repo.settings.writeAll. +// +// Parameters: The complete set of repository-overridable settings to store. +// Internal: WriteAll is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) WriteAll(ctx context.Context, params *RepoSettingsWriteAllRequest) (*RepoSettingsWriteAllResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.writeAll", params) + if err != nil { + return nil, err + } + var result RepoSettingsWriteAllResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteKey writes or removes one allowed top-level repository setting through the existing +// validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing +// documents, and I/O errors reject without replacing the file. Deletion requires +// delete=true; otherwise value must be present. +// +// RPC method: repo.settings.writeKey. +// +// Parameters: One key to write or remove in a repository settings file. +// Internal: WriteKey is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) WriteKey(ctx context.Context, params *RepoSettingsWriteKeyRequest) (*RepoSettingsWriteKeyResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.writeKey", params) + if err != nil { + return nil, err + } + var result RepoSettingsWriteKeyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Settings returns experimental APIs that may change or be removed. +func (s *InternalServerRepoAPI) Settings() *InternalServerRepoSettingsAPI { + return (*InternalServerRepoSettingsAPI)(s) +} + +// Experimental: InternalServerSandboxAPI contains experimental APIs that may change or be +// removed. +type InternalServerSandboxAPI internalServerAPI + +// CheckEnforcementCommand whether one slash command stays reachable while sandbox +// enforcement is unavailable and the session is otherwise blocked. The permitted set is +// deliberately narrow — commands that only report state, and the few that let the user +// repair or leave the situation — and it is keyed on the arguments as well as the name, so +// `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than +// keep its own list: a command this returns false for is one the runtime would refuse +// anyway, and a divergent list either strands the user with no way out or admits a command +// that acts on an unenforced session. +// +// RPC method: sandbox.checkEnforcementCommand. +// +// Parameters: One slash command, as typed, to test against the enforcement-block allowlist. +// +// Returns: True when the command stays available while enforcement is blocked. +// Internal: CheckEnforcementCommand is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) CheckEnforcementCommand(ctx context.Context, params *SandboxEnforcementCommandAllowedParams) (*SandboxCheckEnforcementCommandResult, error) { + raw, err := a.client.Request(ctx, "sandbox.checkEnforcementCommand", params) + if err != nil { + return nil, err + } + var result SandboxCheckEnforcementCommandResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// CheckPlatformSupport reports whether this machine can run an OS-level command sandbox at +// all. A host must ask before it offers sandboxing, because the answer is a property of the +// machine rather than of any setting: on Linux it depends on bubblewrap being installed, +// and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a +// process the first time, so the answer is cached for the life of the runtime. A host that +// assumes support and enables the sandbox anyway produces a session in which every shell +// command fails. +// +// RPC method: sandbox.checkPlatformSupport. +// +// Returns: True when an OS-level sandbox can run on this host. +// Internal: CheckPlatformSupport is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) CheckPlatformSupport(ctx context.Context) (*SandboxCheckPlatformSupportResult, error) { + raw, err := a.client.Request(ctx, "sandbox.checkPlatformSupport", nil) + if err != nil { + return nil, err + } + var result SandboxCheckPlatformSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// CheckWindowsHostLoopbackSupport reports whether this Windows host's BaseContainer +// implementation can reach the host's loopback interface directly, which is what a +// local-network policy needs to avoid routing through the egress proxy. Like +// `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather +// than of any setting, and resolving it the first time spawns a platform probe. A host that +// offers the direct local-network option on a machine that lacks the capability produces a +// session whose sandboxed commands cannot reach local services. Always false off Windows. +// +// RPC method: sandbox.checkWindowsHostLoopbackSupport. +// +// Returns: True when the sandbox on this host can reach host loopback directly. +// Internal: CheckWindowsHostLoopbackSupport is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerSandboxAPI) CheckWindowsHostLoopbackSupport(ctx context.Context) (*SandboxCheckWindowsHostLoopbackSupportResult, error) { + raw, err := a.client.Request(ctx, "sandbox.checkWindowsHostLoopbackSupport", nil) + if err != nil { + return nil, err + } + var result SandboxCheckWindowsHostLoopbackSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// FilterPickerCandidates checks a batch of `@`-file picker suggestions against a policy +// prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, +// positionally aligned with the request. Batched deliberately: each check canonicalizes a +// path component-by-component through the real filesystem, so one call amortizes that over +// a single hop rather than dozens while the user types. A directory the policy does not +// itself allow can still be kept as a waypoint to an allowed subtree. An absent policy +// keeps every candidate. +// +// RPC method: sandbox.filterPickerCandidates. +// +// Parameters: A batch of file-picker candidates to check against a prepared policy. +// +// Returns: Per-candidate allow decisions, positionally aligned with the request. +// Internal: FilterPickerCandidates is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) FilterPickerCandidates(ctx context.Context, params *SandboxFilterPickerCandidatesParams) (*SandboxFilterPickerCandidatesResult, error) { + raw, err := a.client.Request(ctx, "sandbox.filterPickerCandidates", params) + if err != nil { + return nil, err + } + var result SandboxFilterPickerCandidatesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetDocsUrl returns the documentation URL a host should point a user at when it declines +// or downgrades a sandbox setting. The runtime owns the address so every surface cites the +// same page and a host does not hard-code a link that later moves. +// +// RPC method: sandbox.getDocsUrl. +// +// Returns: The documentation URL a host cites when it declines or downgrades a sandbox +// setting. +// Internal: GetDocsUrl is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerSandboxAPI) GetDocsUrl(ctx context.Context) (*SandboxDocsURLResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getDocsUrl", nil) + if err != nil { + return nil, err + } + var result SandboxDocsURLResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetUnsupportedMessage the explanation a host shows when it refuses an explicit request to +// turn the sandbox on for a machine that cannot run one. Carries the platform-specific +// remedy — install bubblewrap, update Windows — and the documentation link, so a host that +// got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason +// and cannot describe the same machine differently from the runtime's own spawn path. +// +// RPC method: sandbox.getUnsupportedMessage. +// +// Returns: The user-facing refusal, including the platform remedy and the documentation +// link. +// Internal: GetUnsupportedMessage is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) GetUnsupportedMessage(ctx context.Context) (*SandboxGetUnsupportedMessageResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getUnsupportedMessage", nil) + if err != nil { + return nil, err + } + var result SandboxGetUnsupportedMessageResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetUnsupportedSettingDisabledNotice the notice a host shows when a stored `sandbox` +// setting is being ignored for this session because the machine cannot enforce it. Distinct +// from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports +// that a setting the user already saved is inert, states that commands will run +// unsandboxed, and confirms the stored setting itself is left alone. A host that stays +// silent here leaves the user believing a sandbox is active. +// +// RPC method: sandbox.getUnsupportedSettingDisabledNotice. +// +// Returns: The user-facing notice that a saved sandbox setting is inert for this session. +// Internal: GetUnsupportedSettingDisabledNotice is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerSandboxAPI) GetUnsupportedSettingDisabledNotice(ctx context.Context) (*SandboxGetUnsupportedSettingDisabledNoticeResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getUnsupportedSettingDisabledNotice", nil) + if err != nil { + return nil, err + } + var result SandboxGetUnsupportedSettingDisabledNoticeResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetUnsupportedStartupNotice the warning a host prints at startup when a session asked for +// a sandbox on a machine that cannot run one. The third of the unsupported notices, and the +// only one that depends on the policy in force: it names the remedy the reader can actually +// act on, which is the stored setting for an unmanaged host, an administrator for a managed +// one, and waiting for the policy to resolve when the sandbox stayed on only because the +// policy could not be determined. Returns no notice when the machine does support a +// sandbox, so a host can call it unconditionally on the startup path. A host that composes +// its own warning tells a managed user to change a setting their policy will overwrite. +// +// RPC method: sandbox.getUnsupportedStartupNotice. +// +// Parameters: The managed sandbox policy in force, which selects which remedy the notice +// offers. +// +// Returns: The startup warning, absent when the machine can run a sandbox. +// Internal: GetUnsupportedStartupNotice is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) GetUnsupportedStartupNotice(ctx context.Context, params *SandboxUnsupportedStartupNoticeParams) (*SandboxUnsupportedStartupNoticeResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getUnsupportedStartupNotice", params) + if err != nil { + return nil, err + } + var result SandboxUnsupportedStartupNoticeResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// PreparePickerPolicy builds the effective filesystem policy one `@`-file picker checks its +// suggestions against, so Git discovery and grant canonicalization run once for the +// picker's lifetime instead of on every debounced keystroke. Returns no policy when the +// sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A +// host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant +// list itself, because the picker's grants are narrower than a file tool's — the same path +// a built-in tool may read can be one the picker must not offer. +// +// RPC method: sandbox.preparePickerPolicy. +// +// Parameters: The working directory and sandbox settings to build a file-picker policy from. +// +// Returns: The prepared file-picker policy, or none when the sandbox is disabled. +// Internal: PreparePickerPolicy is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) PreparePickerPolicy(ctx context.Context, params *SandboxPreparePickerPolicyParams) (*SandboxPreparePickerPolicyResult, error) { + raw, err := a.client.Request(ctx, "sandbox.preparePickerPolicy", params) + if err != nil { + return nil, err + } + var result SandboxPreparePickerPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveFlooredConfig raises a user's sandbox settings to an administrator's managed +// sandbox floor and returns the result a session should actually run under. The floor can +// only tighten: an enterprise force-on is reflected even when the user's own `enabled` is +// false, and a user cannot lower a setting the floor raised. The result is normalized +// through the declared sandbox shape, so a key reorder or an undeclared passthrough key is +// not mistaken for a policy change by callers that diff two results. A host must call this +// rather than merge the two layers itself, because reimplementing the direction of the fold +// is what turns an administrator's floor into a suggestion. +// +// RPC method: sandbox.resolveFlooredConfig. +// +// Parameters: The user's sandbox settings and the managed sandbox floor to raise them to. +// +// Returns: The user's sandbox settings raised to the managed floor. +// Internal: ResolveFlooredConfig is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) ResolveFlooredConfig(ctx context.Context, params *SandboxResolveFlooredConfigParams) (*SandboxResolveFlooredConfigResult, error) { + raw, err := a.client.Request(ctx, "sandbox.resolveFlooredConfig", params) + if err != nil { + return nil, err + } + var result SandboxResolveFlooredConfigResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveForOptional the sandbox a single named feature actually launches under, which is +// not the same as the session's sandbox. A feature is routed out of the sandbox by its own +// flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start +// one server confined and another free. Returns a disabled sandbox rather than an error +// when the host has no sandbox slice at all, so an absent config and an opted-out feature +// read alike at the launch site. A host must ask per feature rather than reuse the session +// config, because reading only `enabled` confines a server the user opted out of, or +// reports as sandboxed one that is not. +// +// RPC method: sandbox.resolveForOptional. +// +// Parameters: A sandbox config and the per-feature routing flag to resolve it for. +// +// Returns: The sandbox a named feature actually launches under. +// Internal: ResolveForOptional is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) ResolveForOptional(ctx context.Context, params *SandboxEffectiveForOptionalParams) (*SandboxEffectiveForOptionalResult, error) { + raw, err := a.client.Request(ctx, "sandbox.resolveForOptional", params) + if err != nil { + return nil, err + } + var result SandboxEffectiveForOptionalResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerSandboxProxySecretAPI contains experimental APIs that may +// change or be removed. +type InternalServerSandboxProxySecretAPI internalServerAPI + +// Delete removes the stored sandbox proxy password from the credential store +// `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to +// call while clearing a proxy password whose origin is unknown. Marked internal because it +// exists to carry a CLI call site off the napi boundary onto the SDK contract. +// +// RPC method: sandbox.proxySecret.delete. +// Internal: Delete is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerSandboxProxySecretAPI) Delete(ctx context.Context) (*SandboxProxySecretDeleteResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.delete", nil) + if err != nil { + return nil, err + } + var result SandboxProxySecretDeleteResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Get reads the stored sandbox proxy password from the credential store +// `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to +// the on-disk store. Reports an absent value rather than failing when no entry exists. +// Marked internal because it exists to carry a CLI call site off the napi boundary onto the +// SDK contract. +// +// RPC method: sandbox.proxySecret.get. +// +// Returns: The stored sandbox proxy password, if one is present. +// Internal: Get is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerSandboxProxySecretAPI) Get(ctx context.Context) (*SandboxProxySecretGetResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.get", nil) + if err != nil { + return nil, err + } + var result SandboxProxySecretGetResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetLocation reports where this runtime keeps the sandbox proxy password: the credential +// store directory and the entry identifier within it. Both are derived from the +// configuration directory this runtime was started with, so a host does not resolve them +// itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this +// runtime's own proxy password rather than a reference the user wrote by hand. Marked +// internal because it exists to carry a CLI call site off the napi boundary onto the SDK +// contract. +// +// RPC method: sandbox.proxySecret.getLocation. +// +// Returns: Where this runtime keeps the sandbox proxy password. +// Internal: GetLocation is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerSandboxProxySecretAPI) GetLocation(ctx context.Context) (*SandboxProxySecretLocation, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.getLocation", nil) + if err != nil { + return nil, err + } + var result SandboxProxySecretLocation + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Save stores the sandbox proxy password in the credential store +// `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether +// the OS keychain accepted it or it fell back to the on-disk store. Marked internal because +// it exists to carry a CLI call site off the napi boundary onto the SDK contract. +// +// RPC method: sandbox.proxySecret.save. +// +// Parameters: The sandbox proxy password to store. +// +// Returns: Where the sandbox proxy password was stored. +// Internal: Save is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerSandboxProxySecretAPI) Save(ctx context.Context, params *SandboxProxySecretSaveRequest) (*SandboxProxySecretSaveResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.save", params) + if err != nil { + return nil, err + } + var result SandboxProxySecretSaveResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: ProxySecret returns experimental APIs that may change or be removed. +func (s *InternalServerSandboxAPI) ProxySecret() *InternalServerSandboxProxySecretAPI { + return (*InternalServerSandboxProxySecretAPI)(s) +} + +// Experimental: InternalServerSandboxSettingsAPI contains experimental APIs that may change +// or be removed. +type InternalServerSandboxSettingsAPI internalServerAPI + +// ApplyDefaults resolves a stored sandbox settings object into the effective one, filling +// every value the user left unset with its default. Read this to render or reason about the +// sandbox configuration a session would actually run under, rather than the sparse document +// the user wrote. +// +// RPC method: sandbox.settings.applyDefaults. +// +// Parameters: The stored sandbox settings to resolve against the defaults. +// +// Returns: The effective sandbox settings, with every unset value resolved to its default. +// Internal: ApplyDefaults is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxSettingsAPI) ApplyDefaults(ctx context.Context, params *SandboxApplyDefaultsRequest) (*SandboxSettingsApplyDefaultsResult, error) { + raw, err := a.client.Request(ctx, "sandbox.settings.applyDefaults", params) + if err != nil { + return nil, err + } + var result SandboxSettingsApplyDefaultsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Settings returns experimental APIs that may change or be removed. +func (s *InternalServerSandboxAPI) Settings() *InternalServerSandboxSettingsAPI { + return (*InternalServerSandboxSettingsAPI)(s) +} + +// Experimental: InternalServerSessionsAPI contains experimental APIs that may change or be +// removed. +type InternalServerSessionsAPI internalServerAPI + +// ConfigureSessionExtensions attaches (or detaches) an in-process ExtensionController +// delegate for the given session in a local host adapter. Pass `controller: undefined` to +// detach. Internal because the controller cannot cross the JSON-RPC boundary; the runtime +// manages its own session extension service. +// +// RPC method: sessions.configureSessionExtensions. +// +// Parameters: Params to attach or detach an in-process ExtensionController delegate. +// Internal: ConfigureSessionExtensions is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSessionsAPI) ConfigureSessionExtensions(ctx context.Context, params *ConfigureSessionExtensionsParams) (*SessionsConfigureSessionExtensionsResult, error) { + raw, err := a.client.Request(ctx, "sessions.configureSessionExtensions", params) + if err != nil { + return nil, err + } + var result SessionsConfigureSessionExtensionsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// CreateWorkspace creates the workspace record for a session that has not been opened yet. +// A host that hands a session off to another application — writing the record and then +// launching that application against the session ID — needs the record on disk before any +// session exists to carry it, which the session-scoped workspace methods cannot do. +// Replaces any existing record and resets the checkpoint index. When writing to the local +// filesystem, a stored `fork_count` survives on disk. Returns the record it built, so a +// surviving stored `fork_count` can differ from the answer. +// +// RPC method: sessions.createWorkspace. +// +// Parameters: Identity, state location and starting context for a workspace record. +// +// Returns: The workspace record that was written. +// Internal: CreateWorkspace is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSessionsAPI) CreateWorkspace(ctx context.Context, params *SessionsCreateWorkspaceRequest) (*SessionsCreateWorkspaceResult, error) { + raw, err := a.client.Request(ctx, "sessions.createWorkspace", params) + if err != nil { + return nil, err + } + var result SessionsCreateWorkspaceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Deletes one local session from disk after running the same lifecycle hooks as the session +// manager. +// +// RPC method: sessions.delete. +// +// Parameters: Session ID to delete from disk. +// Internal: Delete is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerSessionsAPI) Delete(ctx context.Context, params *SessionsDeleteRequest) (*SessionsDeleteResult, error) { + raw, err := a.client.Request(ctx, "sessions.delete", params) + if err != nil { + return nil, err + } + var result SessionsDeleteResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetBoardEntryCount gets the dynamic-context board entry count associated with a session, +// when available. Internal: this exists solely so CLI telemetry events (`rem_spawn_gate`, +// `rem_consolidation_complete`) can pair START / END board counts around the detached +// rem-agent spawn. "Dynamic context board" is a runtime-internal concept that is not part +// of the public SDK contract; the long-term plan is to relocate the telemetry emission into +// the runtime so this method can be deleted entirely. +// +// RPC method: sessions.getBoardEntryCount. +// +// Parameters: Session ID whose board entry count should be returned. +// +// Returns: Dynamic-context board entry count, when available. +// Internal: GetBoardEntryCount is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSessionsAPI) GetBoardEntryCount(ctx context.Context, params *SessionsGetBoardEntryCountRequest) (*SessionsGetBoardEntryCountResult, error) { + raw, err := a.client.Request(ctx, "sessions.getBoardEntryCount", params) + if err != nil { + return nil, err + } + var result SessionsGetBoardEntryCountResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetEventFilePath computes the absolute path to a session's persisted events.jsonl file. +// Internal: filesystem paths are only meaningful in-process (CLI and runtime share a +// filesystem). Currently used by the CLI's contribution-graph feature to read historical +// events directly. Remote SDK consumers must not depend on this; a proper event-query API +// would replace it if the contribution graph ever needed to work over the wire. +// +// RPC method: sessions.getEventFilePath. +// +// Parameters: Session ID whose event-log file path to compute. +// +// Returns: Absolute path to the session's events.jsonl file on disk. +// Internal: GetEventFilePath is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSessionsAPI) GetEventFilePath(ctx context.Context, params *SessionsGetEventFilePathRequest) (*SessionsGetEventFilePathResult, error) { + raw, err := a.client.Request(ctx, "sessions.getEventFilePath", params) + if err != nil { + return nil, err + } + var result SessionsGetEventFilePathResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetMetadata reads lightweight persisted metadata for one local session without opening it. +// +// RPC method: sessions.getMetadata. +// +// Parameters: Session ID whose persisted metadata should be read. +// +// Returns: Persisted local session metadata when the session exists. +// Internal: GetMetadata is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerSessionsAPI) GetMetadata(ctx context.Context, params *SessionsGetMetadataRequest) (*SessionsGetMetadataResult, error) { + raw, err := a.client.Request(ctx, "sessions.getMetadata", params) + if err != nil { + return nil, err + } + var result SessionsGetMetadataResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetPersistedRemoteSteerable returns a session's persisted remote-steerable flag, if any +// has been recorded. Internal: this is CLI-specific book-keeping used by `--continue` / +// `--resume` to inherit the prior session's remote-steerable preference. SDK consumers that +// want similar behavior should manage their own persistence around start/stop calls rather +// than relying on this runtime-side flag. +// +// RPC method: sessions.getPersistedRemoteSteerable. +// +// Parameters: Session ID to look up the persisted remote-steerable flag for. +// +// Returns: The session's persisted remote-steerable flag, or omitted when no value has been +// persisted. +// Internal: GetPersistedRemoteSteerable is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSessionsAPI) GetPersistedRemoteSteerable(ctx context.Context, params *SessionsGetPersistedRemoteSteerableRequest) (*SessionsGetPersistedRemoteSteerableResult, error) { + raw, err := a.client.Request(ctx, "sessions.getPersistedRemoteSteerable", params) + if err != nil { + return nil, err + } + var result SessionsGetPersistedRemoteSteerableResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ListNonEmptySessionIds lists recent local session IDs that contain user-visible history, +// omitting housekeeping-only sessions. +// +// RPC method: sessions.listNonEmptySessionIds. +// +// Parameters: Limit for non-empty local session IDs. +// +// Returns: Recent local session IDs that contain user-visible history. +// Internal: ListNonEmptySessionIds is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSessionsAPI) ListNonEmptySessionIds(ctx context.Context, params *SessionsListNonEmptySessionIDsRequest) (*SessionsListNonEmptySessionIDsResult, error) { + raw, err := a.client.Request(ctx, "sessions.listNonEmptySessionIds", params) + if err != nil { + return nil, err + } + var result SessionsListNonEmptySessionIDsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// LoadWorkspace reads a session's workspace record straight from disk, without opening the +// session. Resuming by session ID has to know where the session lives before it can +// connect, so the lookup cannot come from the session-scoped workspace methods, which +// resolve their location from a live session's context. Returns no record when the file is +// absent. +// +// RPC method: sessions.loadWorkspace. +// +// Parameters: Where the session's state lives, as a root directory and the session ID under +// it. +// +// Returns: The workspace record on disk, omitted when the session has none. +// Internal: LoadWorkspace is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSessionsAPI) LoadWorkspace(ctx context.Context, params *SessionsLoadWorkspaceRequest) (*SessionsLoadWorkspaceResult, error) { + raw, err := a.client.Request(ctx, "sessions.loadWorkspace", params) + if err != nil { + return nil, err + } + var result SessionsLoadWorkspaceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// UpdateWorkspaceFields merges fields into a session's workspace record on disk, creating +// the record when it is absent. The counterpart to `sessions.loadWorkspace`, for the same +// before-the-session-exists case. It preserves stored workspace-schema fields the request +// does not supply, does not preserve stored keys outside the workspace schema, and never +// replaces a stored `fork_count`. +// +// RPC method: sessions.updateWorkspaceFields. +// +// Parameters: Where the session's state lives, plus workspace-schema fields to merge into +// its workspace record. Stored keys outside the schema are not preserved, and a stored +// `fork_count` is never replaced. +// +// Returns: The merge completed. The record carries the supplied workspace-schema fields, +// but a stored `fork_count` stays. +// Internal: UpdateWorkspaceFields is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSessionsAPI) UpdateWorkspaceFields(ctx context.Context, params *SessionsUpdateWorkspaceFieldsRequest) (*SessionsUpdateWorkspaceFieldsResult, error) { + raw, err := a.client.Request(ctx, "sessions.updateWorkspaceFields", params) + if err != nil { + return nil, err + } + var result SessionsUpdateWorkspaceFieldsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerUserAPI contains experimental APIs that may change or be +// removed. +type InternalServerUserAPI internalServerAPI + +// Experimental: InternalServerUserSettingsAPI contains experimental APIs that may change or +// be removed. +type InternalServerUserSettingsAPI internalServerAPI + +// ApplyTopKey validates one top-level setting subtree and writes just that key to +// settings.json as a single step. Doing both here closes the race a caller cannot close +// itself: between a separate preflight read and the write, the file may change. Rewriting +// only the touched key keeps legacy siblings out of settings.json. Answers a status rather +// than failing, so a validation problem and a write problem stay distinguishable. +// +// RPC method: user.settings.applyTopKey. +// +// Parameters: A single top-level setting subtree to validate and write. +// +// Returns: Outcome of validating and writing one top-level setting subtree. +// Internal: ApplyTopKey is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) ApplyTopKey(ctx context.Context, params *UserSettingsApplyTopKeyRequest) (*UserSettingsApplyTopKeyResult, error) { + raw, err := a.client.Request(ctx, "user.settings.applyTopKey", params) + if err != nil { + return nil, err + } + var result UserSettingsApplyTopKeyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// BuildRuntime resolves the effective runtime settings for a host that is about to start a +// session, layering the given overrides over the settings documents, the environment and +// the platform defaults. A host cannot assemble this itself: the precedence between a user +// document, a repository document, the managed layers and the environment is the runtime's +// own rule, and a host that re-implements it drifts from the server it is configuring. The +// working directory, environment and platform are taken as arguments rather than read from +// the server process, so a host resolving settings for a directory other than its own gets +// that directory's answer. Nothing is written; this only computes. +// +// RPC method: user.settings.buildRuntime. +// +// Parameters: The overrides and host context to resolve effective runtime settings from. +// +// Returns: The effective runtime settings, keyed by setting name. Keys this runtime does +// not recognize are preserved rather than dropped, so a caller reading a document written +// by a newer runtime keeps every value. +// Internal: BuildRuntime is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) BuildRuntime(ctx context.Context, params *UserSettingsBuildRuntimeRequest) (*UserSettingsBuildRuntimeResult, error) { + raw, err := a.client.Request(ctx, "user.settings.buildRuntime", params) + if err != nil { + return nil, err + } + var result UserSettingsBuildRuntimeResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// DiagnoseProblems diagnoses a set of already-loaded settings layers, reporting each key +// that will not take effect and why. Settings load tolerantly so that one bad key does not +// stop a session from starting; this method surfaces what was dropped so a caller can +// report it instead of silently ignoring the user's intent. Takes the layers as given +// rather than reading them, so a caller can diagnose exactly the content it is showing, +// including unsaved edits. Never echoes a setting's value, because a value may be a token +// or another secret. Marked internal because it exists to carry a CLI call site off the +// native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer +// needs to inspect settings health itself. +// +// RPC method: user.settings.diagnoseProblems. +// +// Parameters: The settings layers to diagnose. +// +// Returns: The settings that will not take effect across the given layers. +// Internal: DiagnoseProblems is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) DiagnoseProblems(ctx context.Context, params *UserSettingsProblemsRequest) (*UserSettingsProblemsResult, error) { + raw, err := a.client.Request(ctx, "user.settings.diagnoseProblems", params) + if err != nil { + return nil, err + } + var result UserSettingsProblemsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Edit atomically edits one canonical user setting inside its settings-file lock. Reads, +// canonicalizes touched aliases, applies the edit, validates the resulting top-level +// setting and writes before releasing the lock. An explicit autoUpdatesChannel set +// completes the staff migration in the same transaction. Only a malformed existing file +// returns `invalid`; refused keys, invalid values and I/O errors reject the call. // -// RPC method: skills.installations.recover. +// RPC method: user.settings.edit. // -// Parameters: Inventory request under an explicitly selected existing session. +// Parameters: One atomic edit of a canonical setting in settings.json. // -// Returns: Skill installation management result with the honoured contract, or a typed -// refusal. -func (a *ServerSkillsInstallationsAPI) Recover(ctx context.Context, params *SkillInstallationsRequest) (SkillInstallationManagementResult, error) { - raw, err := a.client.Request(ctx, "skills.installations.recover", params) +// Returns: Outcome of an atomic user or repository settings edit. +// Internal: Edit is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerUserSettingsAPI) Edit(ctx context.Context, params *UserSettingsEditRequest) (*SettingsEditResult, error) { + req := map[string]any{} + if params != nil { + req["canonicalPath"] = params.CanonicalPath + if params.ConfigDir != nil { + req["configDir"] = *params.ConfigDir + } + req["operation"] = params.Operation + if params.Value != nil { + req["value"] = params.Value + } + if params.Operation != SettingsEditOperationRemove { + if _, ok := req["value"]; !ok { + req["value"] = nil + } + } + } + raw, err := a.client.Request(ctx, "user.settings.edit", req) if err != nil { return nil, err } - result, err := unmarshalSkillInstallationManagementResult(raw) - if err != nil { + var result SettingsEditResult + if err := json.Unmarshal(raw, &result); err != nil { return nil, err } - return result, nil + return &result, nil } -// SetEnabled atomically persists enablement for one owned Agent Finder Skill and reconciles -// the selected bound session. Enablement is installation-scoped by receipt identity and is -// never gated by the Skill-install feature flag. -// -// RPC method: skills.installations.setEnabled. +// GetPath reports the on-disk path of the settings document `user.settings.load` and +// `user.settings.set` read and write. Resolved the same way those methods resolve it, so a +// host that shows or opens the settings file names the file the runtime actually uses, +// including the extensionless legacy `settings` file when that is what is present. // -// Parameters: Persisted enablement update for one owned Skill installation. +// RPC method: user.settings.getPath. // -// Returns: Skill installation management result with the honoured contract, or a typed -// refusal. -func (a *ServerSkillsInstallationsAPI) SetEnabled(ctx context.Context, params *SkillSetEnabledRequest) (SkillInstallationManagementResult, error) { - raw, err := a.client.Request(ctx, "skills.installations.setEnabled", params) +// Returns: The on-disk location of the user's settings document. +// Internal: GetPath is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) GetPath(ctx context.Context) (*UserSettingsPathResult, error) { + raw, err := a.client.Request(ctx, "user.settings.getPath", nil) if err != nil { return nil, err } - result, err := unmarshalSkillInstallationManagementResult(raw) - if err != nil { + var result UserSettingsPathResult + if err := json.Unmarshal(raw, &result); err != nil { return nil, err } - return result, nil + return &result, nil } -// Status inspects a known Skill installation operation on its original runtime connection. -// Status is never gated by the Skill-install feature flag. +// GetPaths resolves the on-disk locations of the settings files this runtime reads, so a +// consumer can show or open them. The user path is the same file `user.settings.get`, +// `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also +// resolve that repository's checked-in and local settings paths. A path is reported whether +// or not the file exists. // -// RPC method: skills.installations.status. +// RPC method: user.settings.getPaths. // -// Parameters: Existing-operation control. A new session selector is deliberately not -// accepted. +// Parameters: Selects which settings file paths to resolve. // -// Returns: Skill installation management result with the honoured contract, or a typed -// refusal. -func (a *ServerSkillsInstallationsAPI) Status(ctx context.Context, params *SkillInstallationOperationRequest) (SkillInstallationManagementResult, error) { - raw, err := a.client.Request(ctx, "skills.installations.status", params) +// Returns: On-disk locations of the settings files this runtime reads. A path is reported +// whether or not the file exists. +// Internal: GetPaths is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) GetPaths(ctx context.Context, params *UserSettingsGetPathsRequest) (*UserSettingsGetPathsResult, error) { + raw, err := a.client.Request(ctx, "user.settings.getPaths", params) if err != nil { return nil, err } - result, err := unmarshalSkillInstallationManagementResult(raw) - if err != nil { + var result UserSettingsGetPathsResult + if err := json.Unmarshal(raw, &result); err != nil { return nil, err } - return result, nil -} - -// Experimental: Installations returns experimental APIs that may change or be removed. -func (s *ServerSkillsAPI) Installations() *ServerSkillsInstallationsAPI { - return (*ServerSkillsInstallationsAPI)(s) + return &result, nil } -// Experimental: ServerToolsAPI contains experimental APIs that may change or be removed. -type ServerToolsAPI serverAPI - -// Lists built-in tools available for a model. +// GetUnknownKeysWarning reports the top-level keys in the user settings document that the +// runtime does not recognize, phrased for display to the user. This is a separate question +// from the warning `user.settings.loadWithWarning` returns: that one describes parts of the +// document the loader had to ignore to load the rest, whereas an unknown key parses cleanly +// and is simply not a setting, so a host that surfaces only the load warning silently +// accepts a misspelled key that will never take effect. Nothing is reported when the +// document is absent, unreadable, or failed to load, because an unknown-key list derived +// from a document the runtime could not read would be misleading rather than helpful. +// Inspection never modifies the document. // -// RPC method: tools.list. +// RPC method: user.settings.getUnknownKeysWarning. // -// Parameters: Optional model identifier whose tool overrides should be applied to the -// listing. +// Parameters: Selects the configuration directory whose user settings document should be +// inspected for unrecognized top-level keys. // -// 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) { - raw, err := a.client.Request(ctx, "tools.list", params) +// Returns: The unrecognized top-level keys found in the user settings document, already +// phrased for display. +// Internal: GetUnknownKeysWarning is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) GetUnknownKeysWarning(ctx context.Context, params *UserSettingsUnknownKeysWarningRequest) (*UserSettingsUnknownKeysWarningResult, error) { + raw, err := a.client.Request(ctx, "user.settings.getUnknownKeysWarning", params) if err != nil { return nil, err } - var result ToolList + var result UserSettingsUnknownKeysWarningResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: ServerUserAPI contains experimental APIs that may change or be removed. -type ServerUserAPI serverAPI - -// Experimental: ServerUserSettingsAPI contains experimental APIs that may change or be -// removed. -type ServerUserSettingsAPI serverAPI - -// Get lists every known user setting (settings.json overlaid with the legacy config.json, -// config.json wins), each with its effective value, its default, and whether it is at the -// default — so settings the user has never set still appear with their default value. Does -// not include repository- or enterprise-managed overrides that the runtime layers on top at -// session time. +// ListGovernanceKeys lists the top-level user-setting keys by who is allowed to govern +// them: `repo` keys a repository may override through `.github/copilot/settings.json`, +// `claudeRepo` keys a repository may override through a Claude-compatible config, and +// `managed` keys an enterprise policy may fix. The lists are static for a given runtime +// build and fail closed: a key absent from a list cannot be governed that way. // -// RPC method: user.settings.get. +// RPC method: user.settings.listGovernanceKeys. // -// Returns: Per-key metadata for every known user setting (settings.json overlaid with the -// legacy config.json, config.json wins), including settings left at their default. Excludes -// repository- and enterprise-managed overrides. -func (a *ServerUserSettingsAPI) Get(ctx context.Context) (*UserSettingsGetResult, error) { - raw, err := a.client.Request(ctx, "user.settings.get", nil) +// Returns: Top-level user-setting keys grouped by who may govern them. +// Internal: ListGovernanceKeys is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) ListGovernanceKeys(ctx context.Context) (*UserSettingsGovernanceKeysResult, error) { + raw, err := a.client.Request(ctx, "user.settings.listGovernanceKeys", nil) if err != nil { return nil, err } - var result UserSettingsGetResult + var result UserSettingsGovernanceKeysResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Reload drops this runtime process's in-memory user settings cache so the next settings -// read observes disk. +// LoadAndMergeRepo reads a repository's settings and merges them over a supplied user layer +// in one step, returning the settings a consumer should act on inside that repository. Use +// this rather than reading the two layers separately: the merge is per setting and +// collection-aware, so a repository adds to the collections it is allowed to influence +// without replacing the user's own entries, and a whole-document overlay would get that +// wrong. Any diagnostic raised while reading the repository layer is returned rather than +// printed, so the consumer decides how to surface it; the settings that did load are merged +// regardless. +// +// RPC method: user.settings.loadAndMergeRepo. // -// RPC method: user.settings.reload. -func (a *ServerUserSettingsAPI) Reload(ctx context.Context) (*UserSettingsReloadResult, error) { - raw, err := a.client.Request(ctx, "user.settings.reload", nil) +// Parameters: A repository to read settings from, and the user layer they are merged over. +// +// Returns: The settings a consumer should act on inside a repository, together with any +// diagnostic raised while reading the repository layer. +// Internal: LoadAndMergeRepo is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) LoadAndMergeRepo(ctx context.Context, params *UserSettingsLoadAndMergeRepoRequest) (*UserSettingsLoadAndMergeRepoResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadAndMergeRepo", params) if err != nil { return nil, err } - var result UserSettingsReloadResult + var result UserSettingsLoadAndMergeRepoResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Set writes one or more user settings to settings.json, replacing each provided top-level -// key. A key whose value is null is removed. Returns the keys whose new value is shadowed -// by a legacy config.json entry (config.json wins on read), which the runtime leaves in -// place — such writes do not take effect until the legacy value is removed. +// LoadForConfigDir reads the user's settings document exactly as `user.settings.load` does, +// but from a caller-supplied configuration directory instead of the one the server resolved +// for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's +// per-session `configDir` override — so the settings read match the directory that session +// actually uses. An absent or empty `configDir` resolves the server's own home, making this +// identical to `user.settings.load`. Hook-validation relaxations are deliberately not +// caller-supplied: they continue to come from the server's environment, so a consumer +// cannot widen the host's hook policy through this method. // -// RPC method: user.settings.set. +// RPC method: user.settings.loadForConfigDir. // -// Parameters: Partial user settings to write to settings.json. Each top-level key is -// written individually, replacing the existing value; a key whose value is null is removed. +// Parameters: Selects the configuration directory whose user settings to read. // -// Returns: Outcome of writing user settings. -func (a *ServerUserSettingsAPI) Set(ctx context.Context, params *UserSettingsSetRequest) (*UserSettingsSetResult, error) { - raw, err := a.client.Request(ctx, "user.settings.set", params) +// Returns: The stored user settings document, keyed by setting name. +// Internal: LoadForConfigDir is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) LoadForConfigDir(ctx context.Context, params *UserSettingsLoadForConfigDirRequest) (*UserSettingsLoadForConfigDirResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadForConfigDir", params) if err != nil { return nil, err } - var result UserSettingsSetResult + var result UserSettingsLoadForConfigDirResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: Settings returns experimental APIs that may change or be removed. -func (s *ServerUserAPI) Settings() *ServerUserSettingsAPI { - return (*ServerUserSettingsAPI)(s) -} - -// 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 - - Account *ServerAccountAPI - AgentRegistry *ServerAgentRegistryAPI - Agents *ServerAgentsAPI - Catalog *ServerCatalogAPI - Commands *ServerCommandsAPI - Environments *ServerEnvironmentsAPI - Extensions *ServerExtensionsAPI - Hooks *ServerHooksAPI - Host *ServerHostAPI - Instructions *ServerInstructionsAPI - LlmInference *ServerLlmInferenceAPI - ManagedSettings *ServerManagedSettingsAPI - MCP *ServerMCPAPI - Models *ServerModelsAPI - Plugins *ServerPluginsAPI - Runtime *ServerRuntimeAPI - Sandbox *ServerSandboxAPI - Secrets *ServerSecretsAPI - SessionFS *ServerSessionFSAPI - Sessions *ServerSessionsAPI - Skills *ServerSkillsAPI - Tools *ServerToolsAPI - User *ServerUserAPI -} - -// Ping checks server responsiveness and returns protocol information. +// LoadForEdit reads settings.json as stored for a caller that is about to edit it. Unlike +// `user.settings.get`, this returns file values rather than per-key metadata and defaults. +// Reports `missing` for an absent file and `invalid` when the existing file will not parse. +// Retired config.json and extensionless files are not read. // -// RPC method: ping. -// -// Parameters: Optional message to echo back to the caller. +// RPC method: user.settings.loadForEdit. // -// Returns: Server liveness response, including the echoed message, current server -// timestamp, and protocol version. -// Experimental: Ping is an experimental API and may change or be removed in future versions. -func (a *ServerRPC) Ping(ctx context.Context, params *PingRequest) (*PingResult, error) { - raw, err := a.common.client.Request(ctx, "ping", params) +// Returns: Contents of settings.json as stored, for a caller about to rewrite it. +// Internal: LoadForEdit is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) LoadForEdit(ctx context.Context) (*UserSettingsLoadForEditResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadForEdit", nil) if err != nil { return nil, err } - var result PingResult + var result UserSettingsLoadForEditResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// RegisterExtensionLaunchProvider registers the calling SDK client as the per-entrypoint -// extension launch provider. Call before creating any sessions. When omitted, the runtime -// uses its built-in extension launcher. +// LoadRepo reads a repository's checked-in settings document as stored, normalized, +// together with any diagnostic raised while reading it. This is the repository half of the +// layering `user.settings.get` reports: `user.settings.load` reads the user's own document, +// and this reads the one a repository checks in to govern the keys +// `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, +// or that sets a key a repository may not govern, is reported through `warning` while the +// settings that did load are still returned, so a consumer surfaces the diagnostic and +// continues rather than failing the session. When `repoRoot` is the user's home directory +// the Claude-compatible configuration is skipped, so a home-directory session does not +// inherit a personal config as repository policy. // -// RPC method: registerExtensionLaunchProvider. -// Experimental: RegisterExtensionLaunchProvider is an experimental API and may change or be -// removed in future versions. -func (a *ServerRPC) RegisterExtensionLaunchProvider(ctx context.Context) (*RegisterExtensionLaunchProviderResult, error) { - raw, err := a.common.client.Request(ctx, "registerExtensionLaunchProvider", nil) +// RPC method: user.settings.loadRepo. +// +// Parameters: Selects the repository whose checked-in settings to read. +// +// Returns: A repository's settings as stored, together with any diagnostic raised while +// reading them. +// Internal: LoadRepo is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) LoadRepo(ctx context.Context, params *UserSettingsLoadRepoRequest) (*UserSettingsLoadRepoResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadRepo", params) if err != nil { return nil, err } - var result RegisterExtensionLaunchProviderResult + var result UserSettingsLoadRepoResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } 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.Agents = (*ServerAgentsAPI)(&r.common) - r.Catalog = (*ServerCatalogAPI)(&r.common) - r.Commands = (*ServerCommandsAPI)(&r.common) - r.Environments = (*ServerEnvironmentsAPI)(&r.common) - r.Extensions = (*ServerExtensionsAPI)(&r.common) - r.Hooks = (*ServerHooksAPI)(&r.common) - r.Host = (*ServerHostAPI)(&r.common) - r.Instructions = (*ServerInstructionsAPI)(&r.common) - r.LlmInference = (*ServerLlmInferenceAPI)(&r.common) - r.ManagedSettings = (*ServerManagedSettingsAPI)(&r.common) - r.MCP = (*ServerMCPAPI)(&r.common) - r.Models = (*ServerModelsAPI)(&r.common) - r.Plugins = (*ServerPluginsAPI)(&r.common) - r.Runtime = (*ServerRuntimeAPI)(&r.common) - r.Sandbox = (*ServerSandboxAPI)(&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 { - client *jsonrpc2.Client -} - -// Experimental: InternalServerHostAPI contains experimental APIs that may change or be -// removed. -type InternalServerHostAPI internalServerAPI - -// CreateSession requests app-owned materialization over the owning SDK participant. +// LoadWithWarning reads the user's stored settings together with the diagnostic raised +// while reading them. This is `user.settings.load` plus the reason part of the document was +// ignored: that one answers the document alone, so a caller cannot tell a clean read from a +// salvaged one. Read this when the caller is about to write the file back, where accepting +// a partial parse would discard every value the loader could not read. The settings that +// did load are still reported alongside the warning, so a consumer may surface it and +// continue instead of failing. // -// RPC method: host.createSession. -// -// Parameters: One application-owned session handoff, requested by the supervised hosting -// participant. +// RPC method: user.settings.loadWithWarning. // -// Returns: The resident session the application has materialized on its own connection. -// Internal: CreateSession is part of the SDK's internal handshake/plumbing; external +// Returns: The user's stored settings, together with any diagnostic raised while reading +// them. +// Internal: LoadWithWarning is part of the SDK's internal handshake/plumbing; external // callers should not use it. -func (a *InternalServerHostAPI) CreateSession(ctx context.Context, params *HostSessionCreateRequest) (*HostCreateSessionResult, error) { - raw, err := a.client.Request(ctx, "host.createSession", params) +func (a *InternalServerUserSettingsAPI) LoadWithWarning(ctx context.Context) (*UserSettingsLoadWithWarningResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadWithWarning", nil) if err != nil { return nil, err } - var result HostCreateSessionResult + var result UserSettingsLoadWithWarningResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// GetConfiguration returns listener settings only to the supervised hosting participant -// over its SDK connection. +// MergeManagedAndUser folds a user settings layer over a managed (enterprise policy) layer +// and returns the merged settings. The managed layer's governance keys win, `autoTier` +// resolves through its overridable form, and the two per-entry control maps +// (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped +// back from the managed layer, so each entry an administrator declares wins while the user +// keeps control of the rest. The parameters are named for their layers rather than being a +// generic base/override pair: nothing about a settings object identifies which layer +// produced it, so the runtime cannot detect a transposed call, and transposing one resolves +// the governance keys in the user's favour instead of the administrator's. Supplying only +// one layer returns it unchanged, and supplying neither returns an empty object. Rejects a +// managed `autoTier` that is neither a user-configurable tier nor a single-key overridable +// form, rather than silently dropping it. // -// RPC method: host.getConfiguration. +// RPC method: user.settings.mergeManagedAndUser. // -// Returns: Normalized listener settings delivered only to the supervised hosting -// participant. -// Internal: GetConfiguration is part of the SDK's internal handshake/plumbing; external +// Parameters: The managed (enterprise policy) layer and the user layer to fold together. +// The field names carry the layer identity: nothing about a settings object identifies +// which layer produced it, so a generic base/override pair would let a caller transpose +// them and silently resolve the governance keys in the user's favour. +// +// Returns: The user layer folded over the managed layer. +// Internal: MergeManagedAndUser is part of the SDK's internal handshake/plumbing; external // callers should not use it. -func (a *InternalServerHostAPI) GetConfiguration(ctx context.Context) (*HostGetConfigurationResult, error) { - raw, err := a.client.Request(ctx, "host.getConfiguration", nil) +func (a *InternalServerUserSettingsAPI) MergeManagedAndUser(ctx context.Context, params *UserSettingsMergeManagedAndUserParams) (*UserSettingsMergeManagedAndUserResult, error) { + raw, err := a.client.Request(ctx, "user.settings.mergeManagedAndUser", params) if err != nil { return nil, err } - var result HostGetConfigurationResult + var result UserSettingsMergeManagedAndUserResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// GetEnvironmentCredentials resolves current authenticated credentials and remote-control -// policy only for the runtime-owned Mission Control hosting participant. +// MergeRepoValue folds a repository's settings layer into the user layer. Each +// repo-overridable key carries a directional policy chosen so a repository can only add +// restrictions and never relax the user's own. The two per-entry managed control maps are +// the exception those directional rules cannot express — a repository may legitimately +// enable plugins and declare marketplaces — so they are re-stamped afterwards from the +// runtime's ambient managed policy. That makes the result depend on the runtime process's +// managed state and not on the arguments alone: a host must call this rather than +// reimplement the fold, or a repository could relax a restriction the administrator +// imposed. Rejects when either layer is not a JSON object. // -// RPC method: host.getEnvironmentCredentials. +// RPC method: user.settings.mergeRepoValue. // -// Returns: Private credentials delivered only to a runtime-owned Mission Control hosting -// participant. -// Internal: GetEnvironmentCredentials is part of the SDK's internal handshake/plumbing; -// external callers should not use it. -func (a *InternalServerHostAPI) GetEnvironmentCredentials(ctx context.Context) (*HostGetEnvironmentCredentialsResult, error) { - raw, err := a.client.Request(ctx, "host.getEnvironmentCredentials", nil) +// Parameters: The user layer and the repository layer to fold together. +// +// Returns: The repository layer folded into the user layer. +// Internal: MergeRepoValue is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) MergeRepoValue(ctx context.Context, params *UserSettingsMergeRepoValueParams) (*UserSettingsMergeRepoValueResult, error) { + raw, err := a.client.Request(ctx, "user.settings.mergeRepoValue", params) if err != nil { return nil, err } - var result HostGetEnvironmentCredentialsResult + var result UserSettingsMergeRepoValueResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Ready reports a supervised hosting participant's bound AHP endpoint after its SDK -// handshake. +// MigrateObsoleteOnDisk runs the one-time cleanup that removes obsolete CLI-owned settings +// and legacy rubber-duck keys from the user's settings document, and reports what it did. +// Idempotent and safe to call on every startup: with nothing obsolete left it reports +// `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so +// a setting written by a newer host is never dropped by an older one, and a document that +// fails to parse is reported `invalid` and left untouched rather than rewritten from a +// partial read. The cleaned document is not returned: it is written before this replies, so +// `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys +// through `user.settings.unknownKeys` wants this first, because the keys this retires would +// otherwise be shown to the user as if they were misspelled settings. // -// RPC method: host.ready. +// RPC method: user.settings.migrateObsoleteOnDisk. // -// Parameters: Readiness reported by the supervised hosting participant on its own SDK -// connection. +// Parameters: Selects the configuration directory whose settings document to clean. // -// Returns: Empty acknowledgement for a completed host lifecycle operation. -// Internal: Ready is part of the SDK's internal handshake/plumbing; external callers should -// not use it. -func (a *InternalServerHostAPI) Ready(ctx context.Context, params *HostReadyRequest) (*HostReadyResult, error) { - raw, err := a.client.Request(ctx, "host.ready", params) +// Returns: The outcome of the one-time obsolete-settings cleanup. +// Internal: MigrateObsoleteOnDisk is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) MigrateObsoleteOnDisk(ctx context.Context, params *UserSettingsMigrateObsoleteOnDiskRequest) (*UserSettingsMigrateObsoleteOnDiskResult, error) { + raw, err := a.client.Request(ctx, "user.settings.migrateObsoleteOnDisk", params) if err != nil { return nil, err } - var result HostReadyResult + var result UserSettingsMigrateObsoleteOnDiskResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// ReleaseSession releases app ownership retention after AHP detaches. +// MigrateStaffLogLevelOnce runs the one-time migration that moves a staff account's log +// level to the current default, and records that it ran. Idempotent and self-gating: it +// takes a lock over the global-state file and re-reads the completion stamp inside it, so +// two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the +// persisted settings, and the settings it returns are the document re-read after the write, +// so a host should adopt them rather than reloading separately and racing the next writer. // -// RPC method: host.releaseSession. +// RPC method: user.settings.migrateStaffLogLevelOnce. // -// Parameters: Ends one participation, not the application's session lifetime. +// Parameters: Selects the configuration directory to run the one-time staff log-level +// migration against, and supplies the caller's record of whether it has already run. // -// Returns: Empty acknowledgement for a completed host lifecycle operation. -// Internal: ReleaseSession is part of the SDK's internal handshake/plumbing; external -// callers should not use it. -func (a *InternalServerHostAPI) ReleaseSession(ctx context.Context, params *HostSessionReleaseRequest) (*HostReleaseSessionResult, error) { - raw, err := a.client.Request(ctx, "host.releaseSession", params) +// Returns: The outcome of the one-time staff log-level migration. +// Internal: MigrateStaffLogLevelOnce is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) MigrateStaffLogLevelOnce(ctx context.Context, params *UserSettingsMigrateStaffLogLevelOnceRequest) (*UserSettingsMigrateStaffLogLevelOnceResult, error) { + raw, err := a.client.Request(ctx, "user.settings.migrateStaffLogLevelOnce", params) if err != nil { return nil, err } - var result HostReleaseSessionResult + var result UserSettingsMigrateStaffLogLevelOnceResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: InternalServerSessionsAPI contains experimental APIs that may change or be -// removed. -type InternalServerSessionsAPI internalServerAPI - -// ConfigureSessionExtensions attaches (or detaches) an in-process ExtensionController -// delegate for the given session in a local host adapter. Pass `controller: undefined` to -// detach. Internal because the controller cannot cross the JSON-RPC boundary; the runtime -// manages its own session extension service. +// MigrateStaffUpdateChannelOnce runs the one-time migration that moves a staff account's +// update channel to stable, and records that it ran. Idempotent and self-gating: it takes a +// lock over the global-state file, re-reads the completion stamp inside it, and returns +// `current` rather than migrating twice, so two hosts racing at startup cannot both +// migrate. Only a `migrated` status means the persisted settings changed and the caller +// should reload them. An account on the experimental channel is deliberately left alone and +// reported as `excluded-experimental`. // -// RPC method: sessions.configureSessionExtensions. +// RPC method: user.settings.migrateStaffUpdateChannelOnce. // -// Parameters: Params to attach or detach an in-process ExtensionController delegate. -// Internal: ConfigureSessionExtensions is part of the SDK's internal handshake/plumbing; +// Parameters: The filesystem and environment facts a user-settings file is resolved from. +// Passed explicitly rather than read from the runtime's own process, so a host whose +// configuration directory differs from its process environment resolves the file it means. +// +// Returns: The outcome of the one-time staff update-channel migration. +// Internal: MigrateStaffUpdateChannelOnce is part of the SDK's internal handshake/plumbing; // external callers should not use it. -func (a *InternalServerSessionsAPI) ConfigureSessionExtensions(ctx context.Context, params *ConfigureSessionExtensionsParams) (*SessionsConfigureSessionExtensionsResult, error) { - raw, err := a.client.Request(ctx, "sessions.configureSessionExtensions", params) +func (a *InternalServerUserSettingsAPI) MigrateStaffUpdateChannelOnce(ctx context.Context, params *UserSettingsHostContext) (*UserSettingsMigrateStaffUpdateChannelOnceResult, error) { + raw, err := a.client.Request(ctx, "user.settings.migrateStaffUpdateChannelOnce", params) if err != nil { return nil, err } - var result SessionsConfigureSessionExtensionsResult + var result UserSettingsMigrateStaffUpdateChannelOnceResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Deletes one local session from disk after running the same lifecycle hooks as the session -// manager. +// Normalize rewrites legacy and snake_case setting names in a settings object to their +// canonical spelling. A caller editing settings.json must normalize before writing: a +// legacy key left in place survives the write, is re-normalized on the next load, and +// silently shadows the canonical value the write just stored. // -// RPC method: sessions.delete. +// RPC method: user.settings.normalize. // -// Parameters: Session ID to delete from disk. -// Internal: Delete is part of the SDK's internal handshake/plumbing; external callers +// Parameters: Settings object whose key names should be canonicalized. +// +// Returns: Settings object with canonical key names. +// Internal: Normalize is part of the SDK's internal handshake/plumbing; external callers // should not use it. -func (a *InternalServerSessionsAPI) Delete(ctx context.Context, params *SessionsDeleteRequest) (*SessionsDeleteResult, error) { - raw, err := a.client.Request(ctx, "sessions.delete", params) +func (a *InternalServerUserSettingsAPI) Normalize(ctx context.Context, params *UserSettingsNormalizeRequest) (*UserSettingsNormalizeResult, error) { + raw, err := a.client.Request(ctx, "user.settings.normalize", params) if err != nil { return nil, err } - var result SessionsDeleteResult + var result UserSettingsNormalizeResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// GetBoardEntryCount gets the dynamic-context board entry count associated with a session, -// when available. Internal: this exists solely so CLI telemetry events (`rem_spawn_gate`, -// `rem_consolidation_complete`) can pair START / END board counts around the detached -// rem-agent spawn. "Dynamic context board" is a runtime-internal concept that is not part -// of the public SDK contract; the long-term plan is to relocate the telemetry emission into -// the runtime so this method can be deleted entirely. +// ResetStaffModelSelectionOnce runs the one-time reset that clears a staff account's pinned +// model selection, and reports the timestamp the host should record. Idempotent and +// self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the +// timestamp it recorded gets `didReset: false` rather than a second reset. It applies to +// staff accounts only; any other account is reported as not reset without the settings +// document being opened. Only `didReset: true` means the persisted settings changed, and +// only then are the updated settings returned for the host to adopt. // -// RPC method: sessions.getBoardEntryCount. +// RPC method: user.settings.resetStaffModelSelectionOnce. // -// Parameters: Session ID whose board entry count should be returned. +// Parameters: Selects the configuration directory to run the one-time staff model-selection +// reset against, and supplies the caller's record of whether it has already run. // -// Returns: Dynamic-context board entry count, when available. -// Internal: GetBoardEntryCount is part of the SDK's internal handshake/plumbing; external -// callers should not use it. -func (a *InternalServerSessionsAPI) GetBoardEntryCount(ctx context.Context, params *SessionsGetBoardEntryCountRequest) (*SessionsGetBoardEntryCountResult, error) { - raw, err := a.client.Request(ctx, "sessions.getBoardEntryCount", params) +// Returns: The outcome of the one-time staff model-selection reset. +// Internal: ResetStaffModelSelectionOnce is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) ResetStaffModelSelectionOnce(ctx context.Context, params *UserSettingsResetStaffModelSelectionOnceRequest) (*UserSettingsResetStaffModelSelectionOnceResult, error) { + raw, err := a.client.Request(ctx, "user.settings.resetStaffModelSelectionOnce", params) if err != nil { return nil, err } - var result SessionsGetBoardEntryCountResult + var result UserSettingsResetStaffModelSelectionOnceResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// GetEventFilePath computes the absolute path to a session's persisted events.jsonl file. -// Internal: filesystem paths are only meaningful in-process (CLI and runtime share a -// filesystem). Currently used by the CLI's contribution-graph feature to read historical -// events directly. Remote SDK consumers must not depend on this; a proper event-query API -// would replace it if the contribution graph ever needed to work over the wire. +// SetHookDisabled adds or removes one hook key in the user `disabledHooks` setting, +// rewriting settings.json in place and leaving every other setting untouched. Reports a +// typed outcome rather than failing the call, so a host can tell an unparseable settings +// file apart from a write that could not complete. // -// RPC method: sessions.getEventFilePath. +// RPC method: user.settings.setHookDisabled. // -// Parameters: Session ID whose event-log file path to compute. +// Parameters: One hook to disable or re-enable. // -// Returns: Absolute path to the session's events.jsonl file on disk. -// Internal: GetEventFilePath is part of the SDK's internal handshake/plumbing; external +// Returns: Outcome of rewriting the `disabledHooks` setting. +// Internal: SetHookDisabled is part of the SDK's internal handshake/plumbing; external // callers should not use it. -func (a *InternalServerSessionsAPI) GetEventFilePath(ctx context.Context, params *SessionsGetEventFilePathRequest) (*SessionsGetEventFilePathResult, error) { - raw, err := a.client.Request(ctx, "sessions.getEventFilePath", params) +func (a *InternalServerUserSettingsAPI) SetHookDisabled(ctx context.Context, params *UserSettingsSetHookDisabledRequest) (*UserSettingsSetHookDisabledResult, error) { + raw, err := a.client.Request(ctx, "user.settings.setHookDisabled", params) if err != nil { return nil, err } - var result SessionsGetEventFilePathResult + var result UserSettingsSetHookDisabledResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// GetMetadata reads lightweight persisted metadata for one local session without opening it. +// Update merges a partial object into one top-level user setting, re-reading the stored +// value inside this runtime process's settings.json write lock so that concurrent writers +// in this process to different sub-fields of the same key do not clobber each other. Unlike +// `user.settings.set`, which replaces a key's whole value with what the caller last read, +// this keeps sub-fields the caller did not name when both the stored value and supplied +// value are objects; otherwise the supplied value replaces the stored value. Use it +// whenever two independent surfaces own different sub-fields of one setting. Returns the +// key's stored value after the write, in `value`. // -// RPC method: sessions.getMetadata. +// RPC method: user.settings.update. // -// Parameters: Session ID whose persisted metadata should be read. +// Parameters: Names the user setting to merge into, and the partial object to merge. // -// Returns: Persisted local session metadata when the session exists. -// Internal: GetMetadata is part of the SDK's internal handshake/plumbing; external callers +// Returns: The stored value of the user setting after the merge. +// Internal: Update is part of the SDK's internal handshake/plumbing; external callers // should not use it. -func (a *InternalServerSessionsAPI) GetMetadata(ctx context.Context, params *SessionsGetMetadataRequest) (*SessionsGetMetadataResult, error) { - raw, err := a.client.Request(ctx, "sessions.getMetadata", params) +func (a *InternalServerUserSettingsAPI) Update(ctx context.Context, params *UserSettingsUpdateRequest) (*UserSettingsUpdateResult, error) { + raw, err := a.client.Request(ctx, "user.settings.update", params) if err != nil { return nil, err } - var result SessionsGetMetadataResult + var result UserSettingsUpdateResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// GetPersistedRemoteSteerable returns a session's persisted remote-steerable flag, if any -// has been recorded. Internal: this is CLI-specific book-keeping used by `--continue` / -// `--resume` to inherit the prior session's remote-steerable preference. SDK consumers that -// want similar behavior should manage their own persistence around start/stop calls rather -// than relying on this runtime-side flag. +// Validates one top-level setting subtree without writing it, reporting each problem with +// the path it applies to. Scoped to a single top-level key on purpose: validating the whole +// file would reject an edit whenever an unrelated pre-existing field is malformed, locking +// the user out of the very tool that could fix it. // -// RPC method: sessions.getPersistedRemoteSteerable. +// RPC method: user.settings.validate. // -// Parameters: Session ID to look up the persisted remote-steerable flag for. +// Parameters: A single top-level setting subtree to validate. // -// Returns: The session's persisted remote-steerable flag, or omitted when no value has been -// persisted. -// Internal: GetPersistedRemoteSteerable is part of the SDK's internal handshake/plumbing; -// external callers should not use it. -func (a *InternalServerSessionsAPI) GetPersistedRemoteSteerable(ctx context.Context, params *SessionsGetPersistedRemoteSteerableRequest) (*SessionsGetPersistedRemoteSteerableResult, error) { - raw, err := a.client.Request(ctx, "sessions.getPersistedRemoteSteerable", params) +// Returns: Outcome of validating one top-level setting subtree. +// Internal: Validate is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) Validate(ctx context.Context, params *UserSettingsValidateRequest) (*UserSettingsValidateResult, error) { + raw, err := a.client.Request(ctx, "user.settings.validate", params) if err != nil { return nil, err } - var result SessionsGetPersistedRemoteSteerableResult + var result UserSettingsValidateResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// ListNonEmptySessionIds lists recent local session IDs that contain user-visible history, -// omitting housekeeping-only sessions. -// -// RPC method: sessions.listNonEmptySessionIds. +// WriteAll replaces the user settings file's entire content in one write. A key absent from +// `settings` is removed, which is what distinguishes this from `user.settings.set`: that +// one merges, so it can never clear a key the caller has dropped. For a caller saving the +// result of a raw edit, a merge would silently resurrect every key the user deleted. +// Records the same one-time mutation marks a per-key write records, so a setting the user +// has now chosen explicitly stops being migrated for them. // -// Parameters: Limit for non-empty local session IDs. +// RPC method: user.settings.writeAll. // -// Returns: Recent local session IDs that contain user-visible history. -// Internal: ListNonEmptySessionIds is part of the SDK's internal handshake/plumbing; -// external callers should not use it. -func (a *InternalServerSessionsAPI) ListNonEmptySessionIds(ctx context.Context, params *SessionsListNonEmptySessionIDsRequest) (*SessionsListNonEmptySessionIDsResult, error) { - raw, err := a.client.Request(ctx, "sessions.listNonEmptySessionIds", params) +// Parameters: The whole content to store in the user settings file. +// Internal: WriteAll is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) WriteAll(ctx context.Context, params *UserSettingsWriteAllRequest) (*UserSettingsWriteAllResult, error) { + raw, err := a.client.Request(ctx, "user.settings.writeAll", params) if err != nil { return nil, err } - var result SessionsListNonEmptySessionIDsResult + var result UserSettingsWriteAllResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } +// Experimental: Settings returns experimental APIs that may change or be removed. +func (s *InternalServerUserAPI) Settings() *InternalServerUserSettingsAPI { + return (*InternalServerUserSettingsAPI)(s) +} + // InternalServerRPC provides internal SDK server-scoped RPC methods (handshake helpers // etc.). Not part of the public API. type InternalServerRPC struct { // Reuse a single struct instead of allocating one for each service on the heap. common internalServerAPI - Host *InternalServerHostAPI - Sessions *InternalServerSessionsAPI + Account *InternalServerAccountAPI + Agents *InternalServerAgentsAPI + FeatureFlags *InternalServerFeatureFlagsAPI + Git *InternalServerGitAPI + GitHubOwners *InternalServerGitHubOwnersAPI + GitHubRepository *InternalServerGitHubRepositoryAPI + GlobalState *InternalServerGlobalStateAPI + Host *InternalServerHostAPI + Instructions *InternalServerInstructionsAPI + ManagedSettings *InternalServerManagedSettingsAPI + MCP *InternalServerMCPAPI + Permissions *InternalServerPermissionsAPI + Persistence *InternalServerPersistenceAPI + Repo *InternalServerRepoAPI + Sandbox *InternalServerSandboxAPI + Sessions *InternalServerSessionsAPI + User *InternalServerUserAPI } // Connect performs the SDK server connection handshake and validates the optional @@ -29412,8 +36297,23 @@ func (a *InternalServerRPC) Connect(ctx context.Context, params *ConnectRequest) func NewInternalServerRPC(client *jsonrpc2.Client) *InternalServerRPC { r := &InternalServerRPC{} r.common = internalServerAPI{client: client} + r.Account = (*InternalServerAccountAPI)(&r.common) + r.Agents = (*InternalServerAgentsAPI)(&r.common) + r.FeatureFlags = (*InternalServerFeatureFlagsAPI)(&r.common) + r.Git = (*InternalServerGitAPI)(&r.common) + r.GitHubOwners = (*InternalServerGitHubOwnersAPI)(&r.common) + r.GitHubRepository = (*InternalServerGitHubRepositoryAPI)(&r.common) + r.GlobalState = (*InternalServerGlobalStateAPI)(&r.common) r.Host = (*InternalServerHostAPI)(&r.common) + r.Instructions = (*InternalServerInstructionsAPI)(&r.common) + r.ManagedSettings = (*InternalServerManagedSettingsAPI)(&r.common) + r.MCP = (*InternalServerMCPAPI)(&r.common) + r.Permissions = (*InternalServerPermissionsAPI)(&r.common) + r.Persistence = (*InternalServerPersistenceAPI)(&r.common) + r.Repo = (*InternalServerRepoAPI)(&r.common) + r.Sandbox = (*InternalServerSandboxAPI)(&r.common) r.Sessions = (*InternalServerSessionsAPI)(&r.common) + r.User = (*InternalServerUserAPI)(&r.common) return r } @@ -30615,7 +37515,9 @@ func (a *EventLogAPI) Tail(ctx context.Context) (*EventLogTailResult, error) { // Experimental: ExtensionsAPI contains experimental APIs that may change or be removed. type ExtensionsAPI sessionAPI -// Disables an extension for the session. +// Disables an extension for the session and persists the preference when the session has a +// settings store. Hosts synchronizing effective membership should use extensions.reconcile +// instead. // // RPC method: session.extensions.disable. // @@ -30636,7 +37538,9 @@ func (a *ExtensionsAPI) Disable(ctx context.Context, params *ExtensionsDisableRe return &result, nil } -// Enables an extension for the session. +// Enables an extension for the session and persists the preference when the session has a +// settings store. Hosts synchronizing effective membership should use extensions.reconcile +// instead. // // RPC method: session.extensions.enable. // @@ -30675,6 +37579,38 @@ func (a *ExtensionsAPI) List(ctx context.Context) (*ExtensionList, error) { return &result, nil } +// Reconcile host-only reconciliation of authoritative session-effective extension +// membership and enablement. Refreshes runtime-owned discovery and preferences without +// persisting settings, installing plugins, or restarting unchanged activations. Returns +// ExtensionList only after required starts and process/contribution cleanup settle. Takes +// no caller inventory or overrides. Missing controllers, unready/incomplete discovery, +// unavailable workspaces, superseded inputs, and lifecycle failures are errors, not empty +// membership. Independently proven revocations may be applied before an error; retry +// converges without restarting healthy activations. Error data contains +// lifecycleChangesApplied and code: extension_reconciliation_host_required, +// extension_reconciliation_unavailable, extension_reconciliation_not_ready, +// extension_reconciliation_discovery_failed, +// extension_reconciliation_workspace_unavailable, extension_reconciliation_superseded, or +// extension_reconciliation_lifecycle_failed. Mark host reconciliation state applied only on +// success. On older runtimes, method-not-found must not fall back to global discovery and +// persistent extension disables. +// +// RPC method: session.extensions.reconcile. +// +// Returns: Extensions discovered for the session, with their current status. +func (a *ExtensionsAPI) Reconcile(ctx context.Context) (*ExtensionList, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.extensions.reconcile", req) + if err != nil { + return nil, err + } + var result ExtensionList + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Reloads extension definitions and processes for the session. // // RPC method: session.extensions.reload. @@ -31295,10 +38231,8 @@ func (a *MCPAPI) IsServerRunning(ctx context.Context, params *MCPIsServerRunning return &result, nil } -// Lists MCP servers configured for the session, their connection status, and host-level -// state. The host-level state (disabled/filtered servers, failed/needs-auth/pending -// connections, mcp3p policy, full config) is empty/zero when no MCP host has been -// initialized for the session. +// Lists materialized MCP servers and their connection status. Cache misses may start and +// wait for MCP servers. // // RPC method: session.mcp.list. // @@ -31317,6 +38251,27 @@ func (a *MCPAPI) List(ctx context.Context) (*MCPServerList, error) { return &result, nil } +// ListConfigured lists effective MCP configuration without starting, restarting, +// authenticating, or waiting for servers. An optional live observation is from an already +// materialized matching server; this is not a readiness guarantee. +// +// RPC method: session.mcp.listConfigured. +// +// Returns: Effective MCP configuration with optional live observations from matching +// already materialized servers. +func (a *MCPAPI) ListConfigured(ctx context.Context) (*MCPConfiguredServerList, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.mcp.listConfigured", req) + if err != nil { + return nil, err + } + var result MCPConfiguredServerList + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // ListTools lists the tools exposed by a connected MCP server on this session's host. This // performs a live `tools/list` request. Tool UI metadata is returned independently of // whether MCP Apps rendering is enabled for the session. @@ -32148,6 +39103,9 @@ func (a *MetadataAPI) ContextInfo(ctx context.Context, params *MetadataContextIn if params != nil { req["outputTokenLimit"] = params.OutputTokenLimit req["promptTokenLimit"] = params.PromptTokenLimit + if params.ProviderID != nil { + req["providerId"] = *params.ProviderID + } if params.SelectedModel != nil { req["selectedModel"] = *params.SelectedModel } @@ -32475,6 +39433,9 @@ func (a *ModeAPI) Set(ctx context.Context, params *ModeSetRequest) (*ModeSetResu if params.PlanModelConfigured != nil { req["planModelConfigured"] = *params.PlanModelConfigured } + if params.PlanModelProviderID != nil { + req["planModelProviderId"] = *params.PlanModelProviderID + } if params.PlanReasoningEffort != nil { req["planReasoningEffort"] = *params.PlanReasoningEffort } @@ -32518,6 +39479,43 @@ func (a *ModelAPI) GetCurrent(ctx context.Context) (*CurrentModel, error) { return &result, nil } +// GetReasoningSummaries computes whether the session's current model shows reasoning +// summaries and how a host should present them: the default Ctrl+T visibility, reasoning +// headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is +// redundant. The runtime folds in the session's model catalog, selection and +// reasoning-summaries experiment assignment; the host supplies only its own persisted +// setting and current visibility. This method reads the session's resolved model catalog +// rather than resolving it, so call `session.model.list` first on a session that has not +// listed models or run a turn; until then the result is `ready: false`. A session that +// resolves models without a Copilot catalog, that is a BYOK registry or an alternate +// provider, never caches one and stays `ready: false`. +// +// RPC method: session.model.getReasoningSummaries. +// +// Parameters: Host presentation state the reasoning-summaries policy depends on. +// +// Returns: Reasoning-summaries presentation policy for the session's current model. +func (a *ModelAPI) GetReasoningSummaries(ctx context.Context, params *ModelGetReasoningSummariesRequest) (*ModelGetReasoningSummariesResult, error) { + req := map[string]any{"sessionId": a.sessionID} + if params != nil { + if params.PersistedShowReasoning != nil { + req["persistedShowReasoning"] = *params.PersistedShowReasoning + } + if params.SummariesVisible != nil { + req["summariesVisible"] = *params.SummariesVisible + } + } + raw, err := a.client.Request(ctx, "session.model.getReasoningSummaries", req) + if err != nil { + return nil, err + } + var result ModelGetReasoningSummariesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Lists models available to this session using its own auth and integration context. // Connected hosts (CLI TUI, GitHub App) should call this through the session client so // remote sessions return the remote CLI's available models rather than the caller's. @@ -32675,6 +39673,9 @@ func (a *ModelAPI) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) ( if params.PickerPersistence != nil { req["pickerPersistence"] = *params.PickerPersistence } + if params.ProviderID != nil { + req["providerId"] = *params.ProviderID + } if params.ReasoningEffort != nil { req["reasoningEffort"] = *params.ReasoningEffort } @@ -32794,6 +39795,9 @@ func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsPar if params.AgentContext != nil { req["agentContext"] = *params.AgentContext } + if params.AgentDirectories != nil { + req["agentDirectories"] = params.AgentDirectories + } if params.AllowAllMCPServerInstructions != nil { req["allowAllMcpServerInstructions"] = *params.AllowAllMCPServerInstructions } @@ -32872,6 +39876,9 @@ func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsPar if params.FeatureFlags != nil { req["featureFlags"] = params.FeatureFlags } + if params.HookDirectories != nil { + req["hookDirectories"] = params.HookDirectories + } if params.IgnoredSkillsLocations != nil { req["ignoredSkillsLocations"] = params.IgnoredSkillsLocations } @@ -32884,6 +39891,9 @@ func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsPar if params.InstalledPlugins != nil { req["installedPlugins"] = params.InstalledPlugins } + if params.InstructionDirectories != nil { + req["instructionDirectories"] = params.InstructionDirectories + } if params.IntegrationID != nil { req["integrationId"] = *params.IntegrationID } @@ -33785,6 +40795,40 @@ func (a *PluginsAPI) Reload(ctx context.Context, params ...*SessionPluginsReload return &result, nil } +// RetryManaged installs or updates the plugins the session's managed settings require now, +// without waiting for the next automatic attempt after a failure, then reloads plugins. +// Reports progress and failures with the same `session.info` and `session.warning` events +// as automatic preparation. Fails when the runtime does not prepare managed plugins for the +// session. +// +// RPC method: session.plugins.retryManaged. +// +// Parameters: Plugins required by the session's managed settings to install or update again. +// +// Returns: Per-plugin outcomes of retrying the plugins required by the session's managed +// settings. +func (a *PluginsAPI) RetryManaged(ctx context.Context, params ...*SessionPluginsRetryManagedRequest) (*SessionPluginsRetryManagedResult, error) { + var requestParams *SessionPluginsRetryManagedRequest + if len(params) > 0 { + requestParams = params[0] + } + req := map[string]any{"sessionId": a.sessionID} + if requestParams != nil { + if requestParams.Plugins != nil { + req["plugins"] = requestParams.Plugins + } + } + raw, err := a.client.Request(ctx, "session.plugins.retryManaged", req) + if err != nil { + return nil, err + } + var result SessionPluginsRetryManagedResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Uninstalls a plugin when permitted by the live session's retained managed policy. // // RPC method: session.plugins.uninstall. @@ -34528,6 +41572,66 @@ func (a *QueueAPI) WithdrawMessage(ctx context.Context, params *QueueWithdrawMes return &result, nil } +// Experimental: QuotaAPI contains experimental APIs that may change or be removed. +type QuotaAPI sessionAPI + +// Gets the session's current quota and account projection without making a network request. +// +// RPC method: session.quota.get. +// +// Returns: The incumbent session-owned quota and account projection. +func (a *QuotaAPI) Get(ctx context.Context) (*SessionQuotaGetResult, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.quota.get", req) + if err != nil { + return nil, err + } + var result SessionQuotaGetResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Refreshes the session's provider model catalog bypassing its cache, folds quota snapshots +// into session state, and returns the updated projection. Failures leave the last known +// quota intact. +// +// RPC method: session.quota.refresh. +// +// Returns: The incumbent session-owned quota and account projection. +func (a *QuotaAPI) Refresh(ctx context.Context) (*SessionQuotaRefreshResult, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.quota.refresh", req) + if err != nil { + return nil, err + } + var result SessionQuotaRefreshResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// TakeWarnings returns and clears the session's pending quota warnings. Reading or +// refreshing quota does not drain warnings. +// +// RPC method: session.quota.takeWarnings. +// +// Returns: Pending warnings returned and cleared by session.quota.takeWarnings. +func (a *QuotaAPI) TakeWarnings(ctx context.Context) (*SessionQuotaTakeWarningsResult, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.quota.takeWarnings", req) + if err != nil { + return nil, err + } + var result SessionQuotaTakeWarningsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: RemoteAPI contains experimental APIs that may change or be removed. type RemoteAPI sessionAPI @@ -34634,6 +41738,29 @@ func (a *SandboxAPI) DisableForSession(ctx context.Context, params *SandboxDisab return &result, nil } +// GetCredentialSuggestions lists possible secret-bearing environment variables available to +// new sandboxed shells that are not already covered by credential masking. Uses local name +// rules and known-provider host suggestions, never returns secret values, and changes no +// settings or network permissions. Returns no suggestions while the session is not +// sandboxed. +// +// RPC method: session.sandbox.getCredentialSuggestions. +// +// Returns: Possible unconfigured secrets in the sandbox shell environment, sorted by +// variable name, with no secret values. +func (a *SandboxAPI) GetCredentialSuggestions(ctx context.Context) (*SandboxCredentialSuggestionsResult, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.sandbox.getCredentialSuggestions", req) + if err != nil { + return nil, err + } + var result SandboxCredentialSuggestionsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // GetEnforcementStatus returns whether managed policy requires sandbox enforcement and // whether an enforcement failure has permanently blocked the session. // @@ -35472,6 +42599,25 @@ func (a *ToolsAPI) InitializeAndValidate(ctx context.Context) (*ToolsInitializeA return &result, nil } +// ListPendingRequests lists the external tool calls of the session and its sub-agents that +// are still waiting for session.tools.handlePendingToolCall. +// +// RPC method: session.tools.listPendingRequests. +// +// Returns: External tool calls still waiting for a result. +func (a *ToolsAPI) ListPendingRequests(ctx context.Context) (*PendingExternalToolRequestList, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.tools.listPendingRequests", req) + if err != nil { + return nil, err + } + var result PendingExternalToolRequestList + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Set atomically replaces the complete externally implemented tool list supplied by the // calling connection. Built-in, MCP/plugin, extension-discovered, subagent, and tools // supplied by other connections remain unchanged. @@ -36353,6 +43499,9 @@ func (a *WorkspacesAPI) Diff(ctx context.Context, params *WorkspacesDiffRequest) if params.IgnoreWhitespace != nil { req["ignoreWhitespace"] = *params.IgnoreWhitespace } + if params.IncludeContents != nil { + req["includeContents"] = *params.IncludeContents + } req["mode"] = params.Mode } raw, err := a.client.Request(ctx, "session.workspaces.diff", req) @@ -36726,6 +43875,7 @@ type SessionRPC struct { Provider *ProviderAPI Providers *ProvidersAPI Queue *QueueAPI + Quota *QuotaAPI Remote *RemoteAPI Sandbox *SandboxAPI Schedule *ScheduleAPI @@ -37064,6 +44214,7 @@ func NewSessionRPC(client *jsonrpc2.Client, sessionID string) *SessionRPC { r.Provider = (*ProviderAPI)(&r.common) r.Providers = (*ProvidersAPI)(&r.common) r.Queue = (*QueueAPI)(&r.common) + r.Quota = (*QuotaAPI)(&r.common) r.Remote = (*RemoteAPI)(&r.common) r.Sandbox = (*SandboxAPI)(&r.common) r.Schedule = (*ScheduleAPI)(&r.common) @@ -37505,6 +44656,35 @@ func (a *InternalMCPAPI) ReloadWithConfig(ctx context.Context, params *MCPReload return &result, nil } +// SetConnectedIdeInfo records the IDE the host is connected to, so the agent's system +// prompt can name it and its workspace folder. Null or an omitted `ide` clears the recorded +// value, which is how a host reports that it is disconnected; there is no separate clear +// method. Both `ideName` and `workspaceFolder` are required together, because half a state +// cannot be attributed to a project. +// +// RPC method: session.mcp.setConnectedIdeInfo. +// +// Parameters: Records which IDE the host is connected to, or clears it. +// Internal: SetConnectedIdeInfo is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalMCPAPI) SetConnectedIdeInfo(ctx context.Context, params *SessionMCPSetConnectedIdeInfoParams) (*SessionMCPSetConnectedIdeInfoResult, error) { + req := map[string]any{"sessionId": a.sessionID} + if params != nil { + if params.Ide != nil { + req["ide"] = *params.Ide + } + } + raw, err := a.client.Request(ctx, "session.mcp.setConnectedIdeInfo", req) + if err != nil { + return nil, err + } + var result SessionMCPSetConnectedIdeInfoResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // UnregisterExternalClient unregisters a previously registered external MCP client by // server name. Marked internal as the paired companion of `registerExternalClient`: only // in-process callers that registered a client this way can meaningfully unregister it. @@ -37580,6 +44760,9 @@ func (a *InternalModelAPI) ApplyStartupOverlay(ctx context.Context, params *Mode if params.RepoModel != nil { req["repoModel"] = *params.RepoModel } + if params.RepoModelProviderID != nil { + req["repoModelProviderId"] = *params.RepoModelProviderID + } if params.RepoReasoningEffort != nil { req["repoReasoningEffort"] = *params.RepoReasoningEffort } @@ -37598,6 +44781,31 @@ func (a *InternalModelAPI) ApplyStartupOverlay(ctx context.Context, params *Mode return &result, nil } +// ClearStartupSeed clears an unchanged startup model/provider seed before default-model +// resolution. Never clears a resumed or user-selected model. +// +// RPC method: session.model.clearStartupSeed. +// Internal: ClearStartupSeed is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalModelAPI) ClearStartupSeed(ctx context.Context, params *SessionModelClearStartupSeedRequest) (*SessionModelClearStartupSeedResult, error) { + req := map[string]any{"sessionId": a.sessionID} + if params != nil { + req["expectedModel"] = params.ExpectedModel + if params.ExpectedProviderID != nil { + req["expectedProviderId"] = *params.ExpectedProviderID + } + } + raw, err := a.client.Request(ctx, "session.model.clearStartupSeed", req) + if err != nil { + return nil, err + } + var result SessionModelClearStartupSeedResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: InternalQueueAPI contains experimental APIs that may change or be removed. type InternalQueueAPI internalSessionAPI @@ -38125,6 +45333,37 @@ func (a *InternalUIAPI) HandleHumanUserInput(ctx context.Context, params *UIHand return &result, nil } +// Experimental: InternalUsageAPI contains experimental APIs that may change or be removed. +type InternalUsageAPI internalSessionAPI + +// SetCodeChanges internal host-only replacement of absolute code-change totals reported by +// a relay host. +// +// RPC method: session.usage.setCodeChanges. +// +// Parameters: Internal absolute code-change totals reported by the owning host. +// Internal: SetCodeChanges is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalUsageAPI) SetCodeChanges(ctx context.Context, params *SessionUsageSetCodeChangesRequest) (*SessionUsageSetCodeChangesResult, error) { + req := map[string]any{"sessionId": a.sessionID} + if params != nil { + if params.FilesCount != nil { + req["filesCount"] = *params.FilesCount + } + req["linesAdded"] = params.LinesAdded + req["linesRemoved"] = params.LinesRemoved + } + raw, err := a.client.Request(ctx, "session.usage.setCodeChanges", req) + if err != nil { + return nil, err + } + var result SessionUsageSetCodeChangesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: InternalWorkflowAPI contains experimental APIs that may change or be // removed. type InternalWorkflowAPI internalSessionAPI @@ -38234,6 +45473,7 @@ type InternalSessionRPC struct { Schedule *InternalScheduleAPI Settings *InternalSettingsAPI UI *InternalUIAPI + Usage *InternalUsageAPI Workflow *InternalWorkflowAPI } @@ -38282,6 +45522,7 @@ func NewInternalSessionRPC(client *jsonrpc2.Client, sessionID string) *InternalS r.Schedule = (*InternalScheduleAPI)(&r.common) r.Settings = (*InternalSettingsAPI)(&r.common) r.UI = (*InternalUIAPI)(&r.common) + r.Usage = (*InternalUsageAPI)(&r.common) r.Workflow = (*InternalWorkflowAPI)(&r.common) return r } diff --git a/go/rpc/zrpc_encoding.go b/go/rpc/zrpc_encoding.go index 739081b803..fdddf41f89 100644 --- a/go/rpc/zrpc_encoding.go +++ b/go/rpc/zrpc_encoding.go @@ -21,6 +21,12 @@ func unmarshalAuthInfo(data []byte) (AuthInfo, error) { } switch raw.Type { + case AuthInfoTypeAccount: + var d AccountAuthInfo + if err := json.Unmarshal(data, &d); err != nil { + return nil, err + } + return &d, nil case AuthInfoTypeAPIKey: var d APIKeyAuthInfo if err := json.Unmarshal(data, &d); err != nil { @@ -85,6 +91,17 @@ func (r RawAuthInfoData) MarshalJSON() ([]byte, error) { }) } +func (r AccountAuthInfo) MarshalJSON() ([]byte, error) { + type alias AccountAuthInfo + return json.Marshal(struct { + Type AuthInfoType `json:"type"` + alias + }{ + Type: r.Type(), + alias: alias(r), + }) +} + func (r APIKeyAuthInfo) MarshalJSON() ([]byte, error) { type alias APIKeyAuthInfo return json.Marshal(struct { @@ -2990,6 +3007,58 @@ func (r GitHubTokenAcquireResultToken) MarshalJSON() ([]byte, error) { }) } +func (r InstalledPluginSource) MarshalJSON() ([]byte, error) { + if r.InstalledPluginSourceGitHub != nil { + return json.Marshal(r.InstalledPluginSourceGitHub) + } + if r.InstalledPluginSourceLocal != nil { + return json.Marshal(r.InstalledPluginSourceLocal) + } + if r.InstalledPluginSourceURL != nil { + return json.Marshal(r.InstalledPluginSourceURL) + } + if r.String != nil { + return json.Marshal(r.String) + } + return []byte("null"), nil +} + +func (r *InstalledPluginSource) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + *r = InstalledPluginSource{} + return nil + } + { + var value InstalledPluginSourceGitHub + if err := json.Unmarshal(data, &value); err == nil { + *r = InstalledPluginSource{InstalledPluginSourceGitHub: &value} + return nil + } + } + { + var value InstalledPluginSourceLocal + if err := json.Unmarshal(data, &value); err == nil { + *r = InstalledPluginSource{InstalledPluginSourceLocal: &value} + return nil + } + } + { + var value InstalledPluginSourceURL + if err := json.Unmarshal(data, &value); err == nil { + *r = InstalledPluginSource{InstalledPluginSourceURL: &value} + return nil + } + } + { + var value string + if err := json.Unmarshal(data, &value); err == nil { + *r = InstalledPluginSource{String: &value} + return nil + } + } + return errors.New("data did not match any union variant for InstalledPluginSource") +} + func (r *HandlePendingToolCallRequest) UnmarshalJSON(data []byte) error { type rawHandlePendingToolCallRequest struct { Error *string `json:"error,omitempty"` @@ -3543,58 +3612,6 @@ func (r *InstallationConfirmationRequest) UnmarshalJSON(data []byte) error { return nil } -func (r InstalledPluginSource) MarshalJSON() ([]byte, error) { - if r.InstalledPluginSourceGitHub != nil { - return json.Marshal(r.InstalledPluginSourceGitHub) - } - if r.InstalledPluginSourceLocal != nil { - return json.Marshal(r.InstalledPluginSourceLocal) - } - if r.InstalledPluginSourceURL != nil { - return json.Marshal(r.InstalledPluginSourceURL) - } - if r.String != nil { - return json.Marshal(r.String) - } - return []byte("null"), nil -} - -func (r *InstalledPluginSource) UnmarshalJSON(data []byte) error { - if string(data) == "null" { - *r = InstalledPluginSource{} - return nil - } - { - var value InstalledPluginSourceGitHub - if err := json.Unmarshal(data, &value); err == nil { - *r = InstalledPluginSource{InstalledPluginSourceGitHub: &value} - return nil - } - } - { - var value InstalledPluginSourceLocal - if err := json.Unmarshal(data, &value); err == nil { - *r = InstalledPluginSource{InstalledPluginSourceLocal: &value} - return nil - } - } - { - var value InstalledPluginSourceURL - if err := json.Unmarshal(data, &value); err == nil { - *r = InstalledPluginSource{InstalledPluginSourceURL: &value} - return nil - } - } - { - var value string - if err := json.Unmarshal(data, &value); err == nil { - *r = InstalledPluginSource{String: &value} - return nil - } - } - return errors.New("data did not match any union variant for InstalledPluginSource") -} - func matchesMCPSerializableServerConfigMCPServerConfigHTTP(data []byte) bool { var rawGroup0 struct { Command json.RawMessage `json:"command"` @@ -7704,10 +7721,12 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { AdditionalContentExclusionPolicies []SessionOpenOptionsAdditionalContentExclusionPolicy `json:"additionalContentExclusionPolicies,omitzero"` AdditionalDirectories []string `json:"additionalDirectories,omitzero"` AgentContext *string `json:"agentContext,omitempty"` + AgentDirectories []string `json:"agentDirectories,omitzero"` AllowAllMCPServerInstructions *bool `json:"allowAllMcpServerInstructions,omitempty"` AskUserDisabled *bool `json:"askUserDisabled,omitempty"` AuthClientIDMetadataURL *string `json:"authClientIdMetadataUrl,omitempty"` AuthInfo json.RawMessage `json:"authInfo,omitempty"` + AutoTierIsExplicit *bool `json:"autoTierIsExplicit,omitempty"` AvailableTools []string `json:"availableTools,omitzero"` Capi *CapiSessionOptions `json:"capi,omitempty"` ClientKind *string `json:"clientKind,omitempty"` @@ -7729,6 +7748,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { EnableScriptSafety *bool `json:"enableScriptSafety,omitempty"` EnableSkills *bool `json:"enableSkills,omitempty"` EnableStreaming *bool `json:"enableStreaming,omitempty"` + EnforceManagedModelDefaults *bool `json:"enforceManagedModelDefaults,omitempty"` EnvValueMode *SessionOpenOptionsEnvValueMode `json:"envValueMode,omitempty"` EventsLogDirectory *string `json:"eventsLogDirectory,omitempty"` EventsLogIncludesSubagents *bool `json:"eventsLogIncludesSubagents,omitempty"` @@ -7737,10 +7757,12 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { ExpAssignments any `json:"expAssignments,omitempty"` FeatureFlags map[string]bool `json:"featureFlags,omitzero"` HasSkillProvider *bool `json:"hasSkillProvider,omitempty"` + HookDirectories []string `json:"hookDirectories,omitzero"` IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` IncludedBuiltinAgents []string `json:"includedBuiltinAgents,omitzero"` IncludedBuiltinSkills []string `json:"includedBuiltinSkills,omitzero"` InstalledPlugins []InstalledPlugin `json:"installedPlugins,omitzero"` + InstructionDirectories []string `json:"instructionDirectories,omitzero"` IntegrationID *string `json:"integrationId,omitempty"` IsExperimentalMode *bool `json:"isExperimentalMode,omitempty"` LogInteractiveShells *bool `json:"logInteractiveShells,omitempty"` @@ -7784,6 +7806,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { r.AdditionalContentExclusionPolicies = raw.AdditionalContentExclusionPolicies r.AdditionalDirectories = raw.AdditionalDirectories r.AgentContext = raw.AgentContext + r.AgentDirectories = raw.AgentDirectories r.AllowAllMCPServerInstructions = raw.AllowAllMCPServerInstructions r.AskUserDisabled = raw.AskUserDisabled r.AuthClientIDMetadataURL = raw.AuthClientIDMetadataURL @@ -7794,6 +7817,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { } r.AuthInfo = value } + r.AutoTierIsExplicit = raw.AutoTierIsExplicit r.AvailableTools = raw.AvailableTools r.Capi = raw.Capi r.ClientKind = raw.ClientKind @@ -7815,6 +7839,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { r.EnableScriptSafety = raw.EnableScriptSafety r.EnableSkills = raw.EnableSkills r.EnableStreaming = raw.EnableStreaming + r.EnforceManagedModelDefaults = raw.EnforceManagedModelDefaults r.EnvValueMode = raw.EnvValueMode r.EventsLogDirectory = raw.EventsLogDirectory r.EventsLogIncludesSubagents = raw.EventsLogIncludesSubagents @@ -7823,10 +7848,12 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { r.ExpAssignments = raw.ExpAssignments r.FeatureFlags = raw.FeatureFlags r.HasSkillProvider = raw.HasSkillProvider + r.HookDirectories = raw.HookDirectories r.IgnoredSkillsLocations = raw.IgnoredSkillsLocations r.IncludedBuiltinAgents = raw.IncludedBuiltinAgents r.IncludedBuiltinSkills = raw.IncludedBuiltinSkills r.InstalledPlugins = raw.InstalledPlugins + r.InstructionDirectories = raw.InstructionDirectories r.IntegrationID = raw.IntegrationID r.IsExperimentalMode = raw.IsExperimentalMode r.LogInteractiveShells = raw.LogInteractiveShells @@ -8140,6 +8167,12 @@ func unmarshalSettableAuthInfo(data []byte) (SettableAuthInfo, error) { } switch raw.Type { + case SettableAuthInfoTypeAccount: + var d AccountAuthInfo + if err := json.Unmarshal(data, &d); err != nil { + return nil, err + } + return &d, nil case SettableAuthInfoTypeAPIKey: var d APIKeyAuthInfo if err := json.Unmarshal(data, &d); err != nil { diff --git a/go/rpc/zsession_encoding.go b/go/rpc/zsession_encoding.go index fa44772dab..89810fdf9b 100644 --- a/go/rpc/zsession_encoding.go +++ b/go/rpc/zsession_encoding.go @@ -599,6 +599,12 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error { return err } e.Data = &d + case SessionEventTypeSessionManagedPluginProgress: + var d SessionManagedPluginProgressData + if err := json.Unmarshal(raw.Data, &d); err != nil { + return err + } + e.Data = &d case SessionEventTypeSessionManagedSettingsEnforced: var d SessionManagedSettingsEnforcedData if err := json.Unmarshal(raw.Data, &d); err != nil { @@ -677,6 +683,12 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error { return err } e.Data = &d + case SessionEventTypeSessionQuotaObservation: + var d SessionQuotaObservationData + if err := json.Unmarshal(raw.Data, &d); err != nil { + return err + } + e.Data = &d case SessionEventTypeSessionRemoteSteerableChanged: var d SessionRemoteSteerableChangedData if err := json.Unmarshal(raw.Data, &d); err != nil { @@ -2351,6 +2363,8 @@ func (r PermissionPromptRequestWrite) MarshalJSON() ([]byte, error) { func (r *PermissionRequestedData) UnmarshalJSON(data []byte) error { type rawPermissionRequestedData struct { AgentMode *SessionMode `json:"agentMode,omitempty"` + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + OwnerSessionID *string `json:"ownerSessionId,omitempty"` PermissionMode *PermissionMode `json:"permissionMode,omitempty"` PermissionRequest json.RawMessage `json:"permissionRequest"` PromptRequest json.RawMessage `json:"promptRequest,omitempty"` @@ -2364,6 +2378,8 @@ func (r *PermissionRequestedData) UnmarshalJSON(data []byte) error { return err } r.AgentMode = raw.AgentMode + r.OwnerAgentID = raw.OwnerAgentID + r.OwnerSessionID = raw.OwnerSessionID r.PermissionMode = raw.PermissionMode if raw.PermissionRequest != nil { value, err := unmarshalPermissionRequest(raw.PermissionRequest) diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go index b301571f68..cde63686ae 100644 --- a/go/rpc/zsession_events.go +++ b/go/rpc/zsession_events.go @@ -195,6 +195,9 @@ const ( SessionEventTypeSessionInfo SessionEventType = "session.info" SessionEventTypeSessionLimitsExhaustedCompleted SessionEventType = "session_limits_exhausted.completed" SessionEventTypeSessionLimitsExhaustedRequested SessionEventType = "session_limits_exhausted.requested" + // Experimental: SessionEventTypeSessionManagedPluginProgress identifies an experimental + // event that may change or be removed. + SessionEventTypeSessionManagedPluginProgress SessionEventType = "session.managed_plugin_progress" // Experimental: SessionEventTypeSessionManagedSettingsEnforced identifies an experimental // event that may change or be removed. SessionEventTypeSessionManagedSettingsEnforced SessionEventType = "session.managed_settings_enforced" @@ -212,8 +215,11 @@ const ( SessionEventTypeSessionPermissionRecovery SessionEventType = "session.permission_recovery" // Experimental: SessionEventTypeSessionPermissionsChanged identifies an experimental event // that may change or be removed. - SessionEventTypeSessionPermissionsChanged SessionEventType = "session.permissions_changed" - SessionEventTypeSessionPlanChanged SessionEventType = "session.plan_changed" + SessionEventTypeSessionPermissionsChanged SessionEventType = "session.permissions_changed" + SessionEventTypeSessionPlanChanged SessionEventType = "session.plan_changed" + // Experimental: SessionEventTypeSessionQuotaObservation identifies an experimental event + // that may change or be removed. + SessionEventTypeSessionQuotaObservation SessionEventType = "session.quota_observation" SessionEventTypeSessionRemoteSteerableChanged SessionEventType = "session.remote_steerable_changed" SessionEventTypeSessionResume SessionEventType = "session.resume" SessionEventTypeSessionScheduleCancelled SessionEventType = "session.schedule_cancelled" @@ -349,6 +355,18 @@ type PromptCacheBreakData struct { func (*PromptCacheBreakData) sessionEventData() {} func (*PromptCacheBreakData) Type() SessionEventType { return SessionEventTypePromptCacheBreak } +// A provider-owned quota observation, distinct from per-call usage and charge accounting. +// Experimental: SessionQuotaObservationData is part of an experimental API and may change or be removed. +type SessionQuotaObservationData struct { + // The admitted provider's state observation. Admission balances and percentages remain absent; separate monthly usage may report its own amount and cycle. + Observation ProviderQuotaState `json:"observation"` +} + +func (*SessionQuotaObservationData) sessionEventData() {} +func (*SessionQuotaObservationData) Type() SessionEventType { + return SessionEventTypeSessionQuotaObservation +} + // A transient Auto preference failure emitted when the runtime cannot mint or accept a usable model and token pair. The previously effective preference remains active, so SDK clients can surface a non-blocking failure without changing their committed-tier state. This event is ephemeral and is not persisted or replayed on resume. type SessionAutoTierSwitchFailedData struct { // Auto preference that remains effective after the failed request. @@ -432,6 +450,8 @@ type AssistantMessageData struct { ParentToolCallID *string `json:"parentToolCallId,omitempty"` // Generation phase for phased-output models (e.g., thinking vs. response phases) Phase *string `json:"phase,omitempty"` + // Opaque origin provider identity captured at dispatch. Only an exact match with the target provider permits replay of reasoningOpaque, encryptedContent, reasoningBlocks, serverTools, and provider response/item identifiers. Matching model ids or wire protocols is insufficient. Omitted for legacy or unattributed messages; the runtime excludes unproven opaque state when projecting to a known provider. Text content and client tool requests/results remain portable semantic history. + ProviderID *string `json:"providerId,omitempty"` // Neutral provider-tagged reasoning content blocks preserved verbatim for round-tripping. `reasoningText` and `reasoningOpaque` are a lossy derived view of these blocks, retained for display. ReasoningBlocks *AssistantMessageReasoningBlocks `json:"reasoningBlocks,omitempty"` // Opaque/encrypted extended thinking data from Anthropic models. Session-bound and stripped on resume. @@ -467,6 +487,10 @@ type SessionPermissionRecoveryData struct { MaxAttempts int64 `json:"maxAttempts"` // Policy selected from the current client's response capability; mode or client changes may update it during recovery OnBlocked PermissionRecoveryOnBlocked `json:"onBlocked"` + // Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + // Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots + OwnerSessionID *string `json:"ownerSessionId,omitempty"` // Controlled reason for the latest episode transition Reason PermissionRecoveryReason `json:"reason"` // Current lifecycle state of the recovery episode @@ -830,17 +854,24 @@ func (*HumanResponseRecordedData) Type() SessionEventType { // Durable session usage checkpoint for reconstructing aggregate accounting on resume type SessionUsageCheckpointData struct { + // Complete accounting state captured atomically with the receipt watermarks. + // Internal: AccountingSnapshot is part of the SDK's internal API surface and is not intended for external use. + AccountingSnapshot *UsageGetMetricsResult `json:"accountingSnapshot,omitempty"` // Internal per-model prompt-cache state used to restore expiration tracking on resume // Internal: ModelCacheState is part of the SDK's internal API surface and is not intended for external use. ModelCacheState []UsageCheckpointModelCacheState `json:"modelCacheState,omitzero"` // Internal per-conversation prompt-cache-break detector baselines restored on resume // Internal: PromptCacheBreakState is part of the SDK's internal API surface and is not intended for external use. PromptCacheBreakState []any `json:"promptCacheBreakState,omitzero"` + // Provider/model accounting snapshot that subsumes preceding usage receipts. + ProviderModelMetrics []UsageMetricsProviderModelMetric `json:"providerModelMetrics,omitzero"` // Session-wide accumulated nano-AI units cost at checkpoint time TotalNanoAiu float64 `json:"totalNanoAiu"` // Total number of premium API requests used at checkpoint time // Internal: TotalPremiumRequests is part of the SDK's internal API surface and is not intended for external use. TotalPremiumRequests *float64 `json:"totalPremiumRequests,omitempty"` + // Highest accounted sequence per source session; no per-call deduplication history is retained. + UsageAccountingWatermarks map[string]int64 `json:"usageAccountingWatermarks,omitzero"` } func (*SessionUsageCheckpointData) sessionEventData() {} @@ -868,18 +899,20 @@ func (*MCPHeadersRefreshRequiredData) Type() SessionEventType { // Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. // Experimental: SessionManagedSettingsResolvedData is part of an experimental API and may change or be removed. type SessionManagedSettingsResolvedData struct { - // Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + // Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. BypassPermissionsDisabled bool `json:"bypassPermissionsDisabled"` // Whether a session-local permissions layer injected by the SDK host was present ClientManaged *bool `json:"clientManaged,omitempty"` // Whether an actual device MDM/plist/registry/file managed-settings layer was present DeviceManaged bool `json:"deviceManaged"` - // Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + // Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. FailClosed bool `json:"failClosed"` // The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. ManagedKeys []string `json:"managedKeys"` // Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. PermissionsAllowIntersected *bool `json:"permissionsAllowIntersected,omitempty"` + // Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + PermissionsContext *ManagedPermissionsContext `json:"permissionsContext,omitempty"` // Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. PolicyHelperManaged *bool `json:"policyHelperManaged,omitempty"` // Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. @@ -1019,12 +1052,16 @@ type SessionErrorData struct { EligibleForAutoSwitch *bool `json:"eligibleForAutoSwitch,omitempty"` // Fine-grained error code from the upstream provider, when available. For `errorType: "rate_limit"`, this is one of the `RateLimitErrorCode` values (e.g., `"user_weekly_rate_limited"`, `"user_global_rate_limited"`, `"rate_limited"`, `"user_model_rate_limited"`, `"integration_rate_limited"`). For `errorType: "quota"`, this is the CAPI quota error code (e.g., `"quota_exceeded"`, `"session_quota_exceeded"`, `"billing_not_configured"`). ErrorCode *string `json:"errorCode,omitempty"` - // Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") + // Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query") ErrorType string `json:"errorType"` // Human-readable error message Message string `json:"message"` // GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs ProviderCallID *string `json:"providerCallId,omitempty"` + // Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. + ProviderErrorParam *string `json:"providerErrorParam,omitempty"` + // Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). + ProviderErrorType *string `json:"providerErrorType,omitempty"` // What the user must do to recover, when the runtime knows of an action. The `message` never names a client affordance, so a client that offers one — a slash command, a settings pane, a link — renders it from this value. Remediation *RemediationAction `json:"remediation,omitempty"` // Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation @@ -1326,6 +1363,20 @@ func (*AssistantFusionPhaseStartedData) Type() SessionEventType { return SessionEventTypeAssistantFusionPhaseStarted } +// Experimental transient presentation-neutral progress for organization-required plugin preparation. Clients should localize the phase copy and display plugin specs without translating them. +// Experimental: SessionManagedPluginProgressData is part of an experimental API and may change or be removed. +type SessionManagedPluginProgressData struct { + // Current preparation phase. + Phase ManagedPluginProgressPhase `json:"phase"` + // Ordered plugin install specs affected by this phase. Empty while managed settings initialize and when preparation completes. + PluginSpecs []string `json:"pluginSpecs"` +} + +func (*SessionManagedPluginProgressData) sessionEventData() {} +func (*SessionManagedPluginProgressData) Type() SessionEventType { + return SessionEventTypeSessionManagedPluginProgress +} + // Experimental transient signal that HydraFusion routing has started for an eligible turn. // Experimental: SessionFusionRouteStartedData is part of an experimental API and may change or be removed. type SessionFusionRouteStartedData struct { @@ -1430,8 +1481,16 @@ type ModelCallFailureData struct { QuotaSnapshots map[string]AssistantUsageQuotaSnapshot `json:"quotaSnapshots,omitzero"` // Reasoning effort level used for the failed model call, if applicable ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. + RequestBodyBytes *int64 `json:"requestBodyBytes,omitempty"` + // Content-Encoding applied to the failed request body; identity when uncompressed + RequestBodyEncoding *ModelCallRequestBodyEncoding `json:"requestBodyEncoding,omitempty"` + // Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + RequestBodyWireBytes *int64 `json:"requestBodyWireBytes,omitempty"` // Content-free structural summary of the failing request. Contains only counts and shape flags (no prompt content), so it is safe for unrestricted telemetry. Populated only for client-error (4xx) failures. RequestFingerprint *ModelCallFailureRequestFingerprint `json:"requestFingerprint,omitempty"` + // Zero-based orchestrator retry index of the failed attempt + RetryAttempt *int64 `json:"retryAttempt,omitempty"` // Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. Rte *bool `json:"rte,omitempty"` // Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation @@ -1442,6 +1501,20 @@ type ModelCallFailureData struct { StatusCode *int32 `json:"statusCode,omitempty"` // Transport used for the failed model call (http or websocket) Transport *ModelCallFailureTransport `json:"transport,omitempty"` + // Milliseconds spent on the WebSocket attempt before falling back to HTTP + WebsocketFallbackAfterMs *int64 `json:"websocketFallbackAfterMs,omitempty"` + // WebSocket close code received before the HTTP fallback + WebsocketFallbackCloseCode *int32 `json:"websocketFallbackCloseCode,omitempty"` + // Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown + WebsocketFallbackErrorKind *ModelCallWebSocketFallbackErrorKind `json:"websocketFallbackErrorKind,omitempty"` + // Why the failed call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred + WebsocketFallbackReason *ModelCallWebSocketFallbackReason `json:"websocketFallbackReason,omitempty"` + // Whether a WebSocket reconnect was attempted before falling back to HTTP + WebsocketFallbackReconnectAttempted *bool `json:"websocketFallbackReconnectAttempted,omitempty"` + // Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + WebsocketFallbackStartedThisCall *bool `json:"websocketFallbackStartedThisCall,omitempty"` + // HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + WebsocketFallbackStatusCode *int32 `json:"websocketFallbackStatusCode,omitempty"` } func (*ModelCallFailureData) sessionEventData() {} @@ -1716,6 +1789,10 @@ func (*ModelCallFinalResultData) Type() SessionEventType { return SessionEventTy type AssistantUsageData struct { // Number of accepted speculative prediction tokens AcceptedPredictionTokens *int64 `json:"acceptedPredictionTokens,omitempty"` + // Runtime-owned identity shared with the durable accounting receipt. + Accounting *UsageAccountingIdentity `json:"accounting,omitempty"` + // Availability of this call's reported AI-credit amount. Missing billing is unavailable, not a zero charge. + AiCreditsStatus *AiCreditsStatus `json:"aiCreditsStatus,omitempty"` // Completion ID from the model provider (e.g., chatcmpl-abc123) APICallID *string `json:"apiCallId,omitempty"` // API endpoint used for this model call, matching CAPI supported_endpoints vocabulary @@ -1772,6 +1849,8 @@ type AssistantUsageData struct { MaxPromptTokens *int64 `json:"maxPromptTokens,omitempty"` // Model identifier used for this API call Model string `json:"model"` + // Model display name captured for this call, not derived from the current selection. + ModelDisplayName *string `json:"modelDisplayName,omitempty"` // Fixed-set provider family serving the bring-your-own-key model (for example "openai", "anthropic", "azure_openai", "ollama", "llama_cpp", or "other"). Never the caller-supplied provider name. Absent for Copilot-served models. ModelProvider *string `json:"modelProvider,omitempty"` // Number of tool calls returned by the model @@ -1784,6 +1863,8 @@ type AssistantUsageData struct { // Parent tool call ID when this usage originates from a sub-agent // Deprecated: ParentToolCallID is deprecated. ParentToolCallID *string `json:"parentToolCallId,omitempty"` + // Provider identity and product label captured by the actual call's dispatch path. + Provider *ModelProviderRef `json:"provider,omitempty"` // GitHub request tracing ID (x-github-request-id header) for server-side log correlation ProviderCallID *string `json:"providerCallId,omitempty"` // Per-quota resource usage snapshots, keyed by quota identifier @@ -1797,6 +1878,12 @@ type AssistantUsageData struct { ReasoningTokens *int64 `json:"reasoningTokens,omitempty"` // Number of rejected speculative prediction tokens RejectedPredictionTokens *int64 `json:"rejectedPredictionTokens,omitempty"` + // Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. + RequestBodyBytes *int64 `json:"requestBodyBytes,omitempty"` + // Content-Encoding applied to the request body of the attempt that produced this outcome; identity when uncompressed + RequestBodyEncoding *ModelCallRequestBodyEncoding `json:"requestBodyEncoding,omitempty"` + // Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + RequestBodyWireBytes *int64 `json:"requestBodyWireBytes,omitempty"` // Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. Rte *bool `json:"rte,omitempty"` // Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation @@ -1817,6 +1904,20 @@ type AssistantUsageData struct { ToolTokenCount *int64 `json:"toolTokenCount,omitempty"` // Transport used for this model call (http or websocket) Transport *AssistantUsageTransport `json:"transport,omitempty"` + // Milliseconds spent on the WebSocket attempt before falling back to HTTP + WebsocketFallbackAfterMs *int64 `json:"websocketFallbackAfterMs,omitempty"` + // WebSocket close code received before the HTTP fallback + WebsocketFallbackCloseCode *int32 `json:"websocketFallbackCloseCode,omitempty"` + // Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown + WebsocketFallbackErrorKind *ModelCallWebSocketFallbackErrorKind `json:"websocketFallbackErrorKind,omitempty"` + // Why the call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred + WebsocketFallbackReason *ModelCallWebSocketFallbackReason `json:"websocketFallbackReason,omitempty"` + // Whether a WebSocket reconnect was attempted before falling back to HTTP + WebsocketFallbackReconnectAttempted *bool `json:"websocketFallbackReconnectAttempted,omitempty"` + // Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + WebsocketFallbackStartedThisCall *bool `json:"websocketFallbackStartedThisCall,omitempty"` + // HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + WebsocketFallbackStatusCode *int32 `json:"websocketFallbackStatusCode,omitempty"` } func (*AssistantUsageData) sessionEventData() {} @@ -1982,24 +2083,34 @@ func (*ModelCallStartData) Type() SessionEventType { return SessionEventTypeMode type SessionModelChangeData struct { // Committed Auto preference after the model configuration change, when applicable. AutoTier *AutoTier `json:"autoTier,omitempty"` + // True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. + AutoTierManaged *bool `json:"autoTierManaged,omitempty"` // Reason the change happened, when not user-initiated. `"rate_limit_auto_switch"` for changes triggered by the auto-mode-switch rate-limit recovery path, or `"refusal_fallback"` when the active model declined a request (content refusal) and the runtime switched to the configured refusal-fallback model. 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 *ContextTier `json:"contextTier,omitempty"` + // True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. + ContextTierManaged *bool `json:"contextTierManaged,omitempty"` // Newly selected model identifier NewModel string `json:"newModel"` // Previously committed Auto preference, when one was explicitly selected. PreviousAutoTier *AutoTier `json:"previousAutoTier,omitempty"` // Model that was previously selected, if any PreviousModel *string `json:"previousModel,omitempty"` + // Provider of previousModel, when known. A provider-only change is a model selection change even when the model identifiers are equal. + PreviousProviderID *string `json:"previousProviderId,omitempty"` // Reasoning effort level before the model change, if applicable PreviousReasoningEffort *string `json:"previousReasoningEffort,omitempty"` // Reasoning summary mode before the model change, if applicable PreviousReasoningSummary *ReasoningSummary `json:"previousReasoningSummary,omitempty"` // Output verbosity level before the model change, if applicable PreviousVerbosity *Verbosity `json:"previousVerbosity,omitempty"` + // Provider selected for newModel. Omitted for legacy or unattributed selections; never inferred from a later selection. + ProviderID *string `json:"providerId,omitempty"` // Reasoning effort level after the model change, if applicable ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. + ReasoningEffortManaged *bool `json:"reasoningEffortManaged,omitempty"` // Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. ReasoningEffortModel *string `json:"reasoningEffortModel,omitempty"` // Reasoning summary mode after the model change, if applicable @@ -2362,6 +2473,10 @@ func (*PermissionCompletedData) Type() SessionEventType { return SessionEventTyp type PermissionRequestedData struct { // Agent mode captured from the owning turn when permission evaluation began. AgentMode *SessionMode `json:"agentMode,omitempty"` + // Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + // Execution session that owns permission recovery for this request. Absent on historical events. + OwnerSessionID *string `json:"ownerSessionId,omitempty"` // Permission mode captured when evaluation began. Absent on historical events. PermissionMode *PermissionMode `json:"permissionMode,omitempty"` // Details of the permission being requested @@ -2523,18 +2638,18 @@ type SubagentConfiguredData struct { func (*SubagentConfiguredData) sessionEventData() {} func (*SubagentConfiguredData) Type() SessionEventType { return SessionEventTypeSubagentConfigured } -// Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on a bypass-permissions escalation while policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. +// Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on bypass permissions or Assisted Permissions while the corresponding policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. // Experimental: SessionManagedSettingsEnforcedData is part of an experimental API and may change or be removed. type SessionManagedSettingsEnforcedData struct { // The category of runtime action that managed policy governed. Action ManagedSettingsEnforcedAction `json:"action"` - // For a `bypass_permissions_blocked` action, which permission-escalation primitive was refused. Absent for actions without a specific escalation primitive. + // For a `bypass_permissions_blocked` action, which permission-mode or escalation primitive was refused. Absent for actions without a specific primitive. Escalation *ManagedSettingsEnforcedEscalation `json:"escalation,omitempty"` // Whether the enforcement was forced by fail-closed handling (managed policy could not be determined) rather than an explicit managed setting. When true, `setting` still names the restriction that was applied. FailClosed bool `json:"failClosed"` // A human-readable explanation of why the action was governed, suitable for surfacing to the user. Message string `json:"message"` - // The managed setting key responsible for the enforcement (e.g. `permissions.disableBypassPermissionsMode`). + // The managed setting key responsible for the enforcement (for example `permissions.disableBypassPermissionsMode` or `permissions.disableAssistedPermissionsMode`). Setting string `json:"setting"` } @@ -2663,10 +2778,14 @@ type SessionStartData struct { AlreadyInUse *bool `json:"alreadyInUse,omitempty"` // Auto routing preference selected at session creation time AutoTier *AutoTier `json:"autoTier,omitempty"` + // True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. + AutoTierManaged *bool `json:"autoTierManaged,omitempty"` // 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 *ContextTier `json:"contextTier,omitempty"` + // True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. + ContextTierManaged *bool `json:"contextTierManaged,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. @@ -2675,8 +2794,12 @@ type SessionStartData struct { GitHubMCPToolConfig *GitHubMCPToolConfig `json:"githubMcpToolConfig,omitempty"` // Identifier of the software producing the events (e.g., "copilot-agent") Producer string `json:"producer"` + // Provider of selectedModel at creation time, when explicitly selected. + ProviderID *string `json:"providerId,omitempty"` // Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max") ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. + ReasoningEffortManaged *bool `json:"reasoningEffortManaged,omitempty"` // Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. ReasoningEffortModel *string `json:"reasoningEffortModel,omitempty"` // Reasoning summary mode used for model calls, if applicable (e.g. "none", "concise", "detailed") @@ -2745,18 +2868,26 @@ type SessionResumeData struct { AlreadyInUse *bool `json:"alreadyInUse,omitempty"` // Auto routing preference active at resume time AutoTier *AutoTier `json:"autoTier,omitempty"` + // True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. + AutoTierManaged *bool `json:"autoTierManaged,omitempty"` // 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 *ContextTier `json:"contextTier,omitempty"` + // True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. + ContextTierManaged *bool `json:"contextTierManaged,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 or omitted, pending work is normally marked as interrupted unless the resume passively joined live work owned by another client; sessionWasActive distinguishes that case. ContinuePendingWork *bool `json:"continuePendingWork,omitempty"` // Total number of persisted events in the session at the time of resume EventCount int64 `json:"eventCount"` // On-disk byte size of the session's persisted events.jsonl file at resume time; omitted when the file does not exist or cannot be stat'd EventsFileSizeBytes *int64 `json:"eventsFileSizeBytes,omitempty"` + // Provider of selectedModel at resume time, when explicitly selected. + ProviderID *string `json:"providerId,omitempty"` // Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max") ReasoningEffort *string `json:"reasoningEffort,omitempty"` + // True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. + ReasoningEffortManaged *bool `json:"reasoningEffortManaged,omitempty"` // Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. ReasoningEffortModel *string `json:"reasoningEffortModel,omitempty"` // Reasoning summary mode used for model calls, if applicable (e.g. "none", "concise", "detailed") @@ -2795,6 +2926,9 @@ func (*SessionSnapshotRewindData) Type() SessionEventType { // Session termination metrics including usage statistics, code changes, and shutdown reason type SessionShutdownData struct { + // Complete accounting state captured atomically with receipt watermarks. + // Internal: AccountingSnapshot is part of the SDK's internal API surface and is not intended for external use. + AccountingSnapshot *UsageGetMetricsResult `json:"accountingSnapshot,omitempty"` // Per-agent usage breakdown, keyed by agent instance identifier. The main conversation uses the stable key `main`. AgentMetrics map[string]ShutdownAgentMetric `json:"agentMetrics,omitzero"` // Aggregate code change metrics for the session @@ -2811,6 +2945,8 @@ type SessionShutdownData struct { EventsFileSizeBytes *int64 `json:"eventsFileSizeBytes,omitempty"` // Per-model usage breakdown, keyed by model identifier ModelMetrics map[string]ShutdownModelMetric `json:"modelMetrics"` + // Provider/model accounting preserved for replay without consulting current provider selection. + ProviderModelMetrics []UsageMetricsProviderModelMetric `json:"providerModelMetrics,omitzero"` // Unix timestamp (milliseconds) when the session started SessionStartTime int64 `json:"sessionStartTime"` // Whether the session ended normally ("routine") or due to a crash/fatal error ("error") @@ -2829,6 +2965,8 @@ type SessionShutdownData struct { // Total number of premium API requests used during the session // Internal: TotalPremiumRequests is part of the SDK's internal API surface and is not intended for external use. TotalPremiumRequests *float64 `json:"totalPremiumRequests,omitempty"` + // Per-source accounting sequence watermarks subsuming preceding usage receipts. + UsageAccountingWatermarks map[string]int64 `json:"usageAccountingWatermarks,omitzero"` } func (*SessionShutdownData) sessionEventData() {} @@ -3679,6 +3817,8 @@ type CommandsChangedCommand struct { // Token usage breakdown for the compaction LLM call (aligned with assistant.usage format) type CompactionCompleteCompactionTokensUsed struct { + // Whether the compaction's credit amount was reported for all, some, or none of its calls. + AiCreditsStatus *AiCreditsStatus `json:"aiCreditsStatus,omitempty"` // Cached input tokens reused in the compaction LLM call CacheReadTokens *int64 `json:"cacheReadTokens,omitempty"` // Tokens written to prompt cache in the compaction LLM call @@ -3692,8 +3832,14 @@ type CompactionCompleteCompactionTokensUsed struct { InputTokens *int64 `json:"inputTokens,omitempty"` // Model identifier used for the compaction LLM call Model *string `json:"model,omitempty"` + // Model display name captured for the compaction call. + ModelDisplayName *string `json:"modelDisplayName,omitempty"` // Output tokens produced by the compaction LLM call OutputTokens *int64 `json:"outputTokens,omitempty"` + // Provider captured for the compaction call; absent when attribution is unknown. + Provider *ModelProviderRef `json:"provider,omitempty"` + // Number of model requests represented by this aggregated compaction usage + RequestCount *int64 `json:"requestCount,omitempty"` } // Per-request cost and usage data from the CAPI copilot_usage response field @@ -4086,6 +4232,10 @@ type MCPServersLoadedServer struct { // Content-free structural summary of the failing request for diagnosing malformed 4xx calls type ModelCallFailureRequestFingerprint struct { + // Summed byte length of opaque or encrypted reasoning payloads + EncryptedContentBytes *int64 `json:"encryptedContentBytes,omitempty"` + // Summed byte length of inline image payloads (data URLs and base64 sources) + ImageBytes *int64 `json:"imageBytes,omitempty"` // Total number of image content parts ImagePartCount int64 `json:"imagePartCount"` // Image parts whose media type cannot be determined (rejected by strict providers) @@ -4096,6 +4246,8 @@ type ModelCallFailureRequestFingerprint struct { MessageCount int64 `json:"messageCount"` // Tool calls whose name is missing or empty (rejected by strict providers) NamelessToolCallCount int64 `json:"namelessToolCallCount"` + // Number of messages carrying opaque or encrypted reasoning + ReasoningItemCount *int64 `json:"reasoningItemCount,omitempty"` // Total number of tool calls across assistant messages ToolCallCount int64 `json:"toolCallCount"` // Number of "tool" result messages in the request @@ -4450,6 +4602,8 @@ type PermissionPromptRequestWrite struct { CanOfferSessionApproval bool `json:"canOfferSessionApproval"` // Unified diff showing the proposed changes Diff string `json:"diff"` + // Complete before/after text previews captured while planning this request. Omitted when a complete preview is unavailable, including pre-read sandbox requests and non-UTF-8 files. Missing sides mean creation or deletion, not unavailable content. + FileEdits []PermissionWriteFileEdit `json:"fileEdits,omitzero"` // Path of the file being written to FileName string `json:"fileName"` // Human-readable description of the intended file change @@ -4779,6 +4933,8 @@ type PermissionRequestWrite struct { CanOfferSessionApproval bool `json:"canOfferSessionApproval"` // Unified diff showing the proposed changes Diff string `json:"diff"` + // Complete before/after text previews captured while planning this request. Omitted when a complete preview is unavailable, including pre-read sandbox requests and non-UTF-8 files. Missing sides mean creation or deletion, not unavailable content. + FileEdits []PermissionWriteFileEdit `json:"fileEdits,omitzero"` // Path of the file being written to FileName string `json:"fileName"` // Human-readable description of the intended file change @@ -4977,6 +5133,22 @@ type PermissionSandboxPathGrant struct { RemovedReadonlyPaths []string `json:"removedReadonlyPaths,omitzero"` } +// A named, complete UTF-8 text snapshot for a pending file operation. +type PermissionWriteFileContent struct { + // Complete file contents, including an empty string for an empty file. + Content string `json:"content"` + // Absolute path in the session filesystem namespace. + Path string `json:"path"` +} + +// Complete text snapshots for one proposed file change. At least one side is present. Different before and after paths describe a move. +type PermissionWriteFileEdit struct { + // Complete file content the operation plans to write. Absent only when the file is being deleted. + After *PermissionWriteFileContent `json:"after,omitempty"` + // File content read while planning the operation. Absent only when the file is being created. + Before *PermissionWriteFileContent `json:"before,omitempty"` +} + // A model-facing binary result as persisted: full inline data, a size-omitted marker, or a deduplicated asset reference // Experimental: PersistedBinaryResult is part of an experimental API and may change or be removed. type PersistedBinaryResult interface { @@ -5705,6 +5877,16 @@ type ToolExecutionStartToolDescriptionMetaUI struct { Visibility []ToolExecutionStartToolDescriptionMetaUIVisibility `json:"visibility,omitzero"` } +// Ordered accounting identity assigned under the source session's emission lock. +type UsageAccountingIdentity struct { + // Monotonically increasing sequence within the source session. + Sequence int64 `json:"sequence"` + // Session that assigned this accounting sequence. + SourceSessionID string `json:"sourceSessionId"` + // Existing API call identifier, or a runtime-generated identity when none was supplied. + UsageID string `json:"usageId"` +} + // Internal prompt-cache expiration state for one model // Internal: UsageCheckpointModelCacheState is an internal SDK API and is not part of the public surface. type UsageCheckpointModelCacheState struct { @@ -6203,15 +6385,30 @@ const ( HumanResponseRecordedResponseResponseKindUserInput HumanResponseRecordedResponseResponseKind = "user_input" ) +// Current phase of organization-required plugin preparation. +// Experimental: ManagedPluginProgressPhase is part of an experimental API and may change or be removed. +type ManagedPluginProgressPhase string + +const ( + // Managed plugin preparation has completed. + ManagedPluginProgressPhaseComplete ManagedPluginProgressPhase = "complete" + // Managed settings are still resolving before plugin preparation can be planned. + ManagedPluginProgressPhaseInitializing ManagedPluginProgressPhase = "initializing" + // Required plugin content is being installed. + ManagedPluginProgressPhaseInstalling ManagedPluginProgressPhase = "installing" + // Installed required plugin content is being updated. + ManagedPluginProgressPhaseUpdating ManagedPluginProgressPhase = "updating" +) + // The category of runtime action that enterprise managed settings governed (blocked or capped) type ManagedSettingsEnforcedAction string const ( - // An attempt to turn on a bypass-permissions ("yolo") escalation was refused or capped because policy disables bypass-permissions mode. + // An attempt to enter a permission mode governed by managed policy was refused or capped. The `setting` and `escalation` fields identify whether this was bypass permissions or Assisted Permissions. ManagedSettingsEnforcedActionBypassPermissionsBlocked ManagedSettingsEnforcedAction = "bypass_permissions_blocked" ) -// For a `bypass_permissions_blocked` action, which permission-escalation primitive was refused +// For a `bypass_permissions_blocked` action, which permission-mode or escalation primitive was refused type ManagedSettingsEnforcedEscalation string const ( @@ -6219,7 +6416,7 @@ const ( ManagedSettingsEnforcedEscalationAllowAll ManagedSettingsEnforcedEscalation = "allow_all" // Automatic approval of all tool permission requests. ManagedSettingsEnforcedEscalationApproveAll ManagedSettingsEnforcedEscalation = "approve_all" - // Assisted mode — keeps normal prompt paths and adds an LLM recommendation, distinct from allow-all. + // Assisted Permissions — uses an LLM review to reduce prompts, distinct from allow-all and not a hard security boundary. ManagedSettingsEnforcedEscalationAssistedApproval ManagedSettingsEnforcedEscalation = "assisted_approval" // A server-wide MCP "Always Allow" (or `--allow-tool `) blanket that would auto-approve every tool from an MCP server. Capped to per-tool approval; each tool still prompts. ManagedSettingsEnforcedEscalationServerWideMCPApproval ManagedSettingsEnforcedEscalation = "server_wide_mcp_approval" @@ -6378,6 +6575,64 @@ const ( ModelCallFinishedOutcomeSuccess ModelCallFinishedOutcome = "success" ) +// Content-Encoding applied to the request body sent on the wire +type ModelCallRequestBodyEncoding string + +const ( + // The request body was sent gzip-compressed. + ModelCallRequestBodyEncodingGzip ModelCallRequestBodyEncoding = "gzip" + // The request body was sent uncompressed (including every WebSocket request). + ModelCallRequestBodyEncodingIdentity ModelCallRequestBodyEncoding = "identity" + // The request body was sent zstd-compressed. + ModelCallRequestBodyEncodingZstd ModelCallRequestBodyEncoding = "zstd" +) + +// Normalized cause of the WebSocket failure that triggered the HTTP fallback +type ModelCallWebSocketFallbackErrorKind string + +const ( + // The peer closed the WebSocket. + ModelCallWebSocketFallbackErrorKindClosedByPeer ModelCallWebSocketFallbackErrorKind = "closed_by_peer" + // The runtime closed the WebSocket itself. + ModelCallWebSocketFallbackErrorKindClosedLocally ModelCallWebSocketFallbackErrorKind = "closed_locally" + // The WebSocket request could not be built. + ModelCallWebSocketFallbackErrorKindConfiguration ModelCallWebSocketFallbackErrorKind = "configuration" + // The peer refused the TCP connection. + ModelCallWebSocketFallbackErrorKindConnectionRefused ModelCallWebSocketFallbackErrorKind = "connection_refused" + // The connection was reset, aborted, or ended mid-stream without a close. + ModelCallWebSocketFallbackErrorKindConnectionReset ModelCallWebSocketFallbackErrorKind = "connection_reset" + // DNS resolution of the WebSocket host failed. + ModelCallWebSocketFallbackErrorKindDns ModelCallWebSocketFallbackErrorKind = "dns" + // The upgrade or request was rejected with an HTTP status. + ModelCallWebSocketFallbackErrorKindHTTPStatus ModelCallWebSocketFallbackErrorKind = "http_status" + // The socket was already closed before it was used. + ModelCallWebSocketFallbackErrorKindNotConnected ModelCallWebSocketFallbackErrorKind = "not_connected" + // A failure that maps onto none of the other kinds. + ModelCallWebSocketFallbackErrorKindOther ModelCallWebSocketFallbackErrorKind = "other" + // A WebSocket protocol violation or an undecodable frame. + ModelCallWebSocketFallbackErrorKindProtocol ModelCallWebSocketFallbackErrorKind = "protocol" + // A WebSocket connect or read timed out. + ModelCallWebSocketFallbackErrorKindTimeout ModelCallWebSocketFallbackErrorKind = "timeout" + // The TLS handshake or a TLS record failed. + ModelCallWebSocketFallbackErrorKindTls ModelCallWebSocketFallbackErrorKind = "tls" +) + +// Why a WebSocket-capable model call was carried by the HTTP fallback +type ModelCallWebSocketFallbackReason string + +const ( + // The WebSocket returned a retryable API error. + ModelCallWebSocketFallbackReasonAPIError ModelCallWebSocketFallbackReason = "api_error" + // The WebSocket connection could not be established. + ModelCallWebSocketFallbackReasonConnectFailed ModelCallWebSocketFallbackReason = "connect_failed" + // No usable WebSocket connection was available for the request. + ModelCallWebSocketFallbackReasonConnectionUnavailable ModelCallWebSocketFallbackReason = "connection_unavailable" + // Sending the request over the WebSocket failed. + ModelCallWebSocketFallbackReasonSendFailed ModelCallWebSocketFallbackReason = "send_failed" + // The WebSocket transport failed before any output reached the consumer. + ModelCallWebSocketFallbackReasonTransportFailed ModelCallWebSocketFallbackReason = "transport_failed" +) + // Why the session no longer has an explicitly selected model. type ModelDeselectedReason string @@ -6440,6 +6695,14 @@ const ( PermissionApprovalEvaluationReasonCodeArgumentBindingUnreviewable PermissionApprovalEvaluationReasonCode = "argument-binding-unreviewable" // The judge was skipped because authorization extraction could not safely establish a complete recent history. PermissionApprovalEvaluationReasonCodeAuthorizationHistoryIncomplete PermissionApprovalEvaluationReasonCode = "authorization-history-incomplete" + // A code source was excluded from review by content exclusion policy. + PermissionApprovalEvaluationReasonCodeContentExcluded PermissionApprovalEvaluationReasonCode = "content-excluded" + // The shell command used a code source computed at run time. + PermissionApprovalEvaluationReasonCodeDynamicSource PermissionApprovalEvaluationReasonCode = "dynamic-source" + // A code-bearing executable exceeded the binding size limit. + PermissionApprovalEvaluationReasonCodeExecutableTooLarge PermissionApprovalEvaluationReasonCode = "executable-too-large" + // A code-bearing executable could not be inspected. + PermissionApprovalEvaluationReasonCodeExecutableUnavailable PermissionApprovalEvaluationReasonCode = "executable-unavailable" // Assisted approval was inactive for this request. PermissionApprovalEvaluationReasonCodeInactive PermissionApprovalEvaluationReasonCode = "inactive" // The request inherited an outcome from another decision. @@ -6476,6 +6739,8 @@ const ( PermissionApprovalEvaluationReasonCodeShellEnvironmentUnreviewable PermissionApprovalEvaluationReasonCode = "shell-environment-unreviewable" // The script snapshot exceeded the size limit. PermissionApprovalEvaluationReasonCodeTooLarge PermissionApprovalEvaluationReasonCode = "too-large" + // The shell command referenced more code sources than can be reviewed. + PermissionApprovalEvaluationReasonCodeTooManySources PermissionApprovalEvaluationReasonCode = "too-many-sources" // Script review was unavailable. PermissionApprovalEvaluationReasonCodeUnavailable PermissionApprovalEvaluationReasonCode = "unavailable" // Attribution is missing or outside the supported vocabulary. @@ -6486,6 +6751,10 @@ const ( PermissionApprovalEvaluationReasonCodeUnrepresentablePath PermissionApprovalEvaluationReasonCode = "unrepresentable-path" // The script invocation could not be reviewed. PermissionApprovalEvaluationReasonCodeUnreviewableScriptInvocation PermissionApprovalEvaluationReasonCode = "unreviewable-script-invocation" + // The shell command could not be analyzed for execution evidence. + PermissionApprovalEvaluationReasonCodeUnsupportedCommandShape PermissionApprovalEvaluationReasonCode = "unsupported-command-shape" + // The shell command used a code source that cannot be bound for review. + PermissionApprovalEvaluationReasonCodeUnsupportedSource PermissionApprovalEvaluationReasonCode = "unsupported-source" ) // Direction stored in a historical extractor claim. Current runtimes do not apply it. @@ -6644,7 +6913,7 @@ const ( PlanChangedOperationUpdate PlanChangedOperation = "update" ) -// Auto preferences that Copilot API can recommend. +// Enabled Auto preferences that Copilot API can recommend. type RecommendedAutoTier string const ( diff --git a/go/session.go b/go/session.go index 45113a59ac..870b3f836f 100644 --- a/go/session.go +++ b/go/session.go @@ -62,9 +62,10 @@ type Session struct { transcriptRecovery *TranscriptRecoveryReport client *jsonrpc2.Client clientSessionAPIs *rpc.ClientSessionAPIHandlers - handlers []sessionHandler + handlers []*sessionHandler nextHandlerID uint64 handlerMutex sync.RWMutex + gracefulRetirement bool toolHandlers map[string]ToolHandler toolHandlersM sync.RWMutex setToolsOnce sync.Once @@ -93,6 +94,8 @@ type Session struct { elicitationMu sync.RWMutex canvasHandler CanvasHandler canvasMu sync.RWMutex + skillProvider SkillProvider + skillProviderMu sync.RWMutex bearerTokenProviders map[string]BearerTokenProvider bearerTokenMu sync.RWMutex releaseGitHubTokenProvider func() @@ -221,6 +224,24 @@ func (s *Session) getCanvasHandler() CanvasHandler { return s.canvasHandler } +func (s *Session) registerSkillProvider(provider SkillProvider) { + s.skillProviderMu.Lock() + defer s.skillProviderMu.Unlock() + s.skillProvider = provider +} + +func (s *Session) getSkillProvider() SkillProvider { + s.skillProviderMu.RLock() + defer s.skillProviderMu.RUnlock() + return s.skillProvider +} + +func (s *Session) clearSkillProvider() { + s.skillProviderMu.Lock() + s.skillProvider = nil + s.skillProviderMu.Unlock() +} + // registerBearerTokenProviders installs per-provider [BearerTokenProvider] callbacks // for BYOK providers configured with managed-identity / on-demand bearer-token // auth, keyed by provider name. @@ -406,7 +427,7 @@ func newSession( managedSettings: managedSettings, client: client, clientSessionAPIs: &rpc.ClientSessionAPIHandlers{}, - handlers: make([]sessionHandler, 0), + handlers: make([]*sessionHandler, 0), toolHandlers: make(map[string]ToolHandler), commandHandlers: make(map[string]CommandHandler), eventCh: make(chan SessionEvent, 128), @@ -493,7 +514,7 @@ func (s *Session) SendPrompt(ctx context.Context, prompt string) (string, error) // // Events are still delivered to handlers registered via [Session.On] while waiting. // Synchronous handlers registered before this call finish processing the completing -// root session.idle event before it returns successfully. +// root session.idle event before it returns successfully, unless the session retires. // This does not wait for asynchronous work started by a handler. // Sub-agent events with a non-empty AgentID do not complete the wait or supply its reply. // @@ -503,7 +524,7 @@ func (s *Session) SendPrompt(ctx context.Context, prompt string) (string, error) // Controls how long to wait; does not abort in-flight agent work. // // Returns the final assistant message event, or nil if none was received. -// Returns an error if the timeout is reached or the connection fails. +// Returns an error if the timeout is reached, the session is closed, or the connection fails. // // Example: // @@ -528,34 +549,56 @@ func (s *Session) SendAndWait(ctx context.Context, options MessageOptions) (*Ses defer cancel() } - idleCh := make(chan struct{}, 1) - errCh := make(chan error, 1) + type outcome struct { + event *SessionEvent + err error + } + terminalCh := make(chan outcome, 1) + dispatchedCh := make(chan struct{}, 1) var lastAssistantMessage *SessionEvent - var mu sync.Mutex + completed := false + finish := func(result outcome) { + if !completed { + completed = true + terminalCh <- result + } + } - unsubscribe := s.On(func(event SessionEvent) { - if event.AgentID != nil && *event.AgentID != "" { + // Observe the result before user callbacks can retire the current dispatch. + unobserve := s.on(func(event SessionEvent) { + if completed || (event.AgentID != nil && *event.AgentID != "") { return } switch d := event.Data.(type) { case *AssistantMessageData: - mu.Lock() eventCopy := event lastAssistantMessage = &eventCopy - mu.Unlock() case *SessionIdleData: if d.Mode != nil && *d.Mode == SessionModeAutopilot { break } - select { - case idleCh <- struct{}{}: - default: - } + finish(outcome{event: lastAssistantMessage}) case *SessionErrorData: - select { - case errCh <- fmt.Errorf("session error: %s", d.Message): - default: + finish(outcome{err: fmt.Errorf("session error: %s", d.Message)}) + } + }, true) + defer unobserve() + unsubscribe := s.On(func(event SessionEvent) { + if event.AgentID != nil && *event.AgentID != "" { + return + } + switch data := event.Data.(type) { + case *SessionIdleData: + if data.Mode != nil && *data.Mode == SessionModeAutopilot { + return } + case *SessionErrorData: + default: + return + } + select { + case dispatchedCh <- struct{}{}: + default: } }) defer unsubscribe() @@ -566,16 +609,27 @@ func (s *Session) SendAndWait(ctx context.Context, options MessageOptions) (*Ses } select { - case <-idleCh: - mu.Lock() - result := lastAssistantMessage - mu.Unlock() - return result, nil - case err := <-errCh: - return nil, err + case <-dispatchedCh: + case <-s.eventDone: + s.handlerMutex.RLock() + graceful := s.gracefulRetirement + s.handlerMutex.RUnlock() + if !graceful { + select { + case <-dispatchedCh: + default: + return nil, errors.New("session closed before response completed") + } + } case <-ctx.Done(): return nil, fmt.Errorf("waiting for session.idle: %w", ctx.Err()) } + select { + case result := <-terminalCh: + return result.event, result.err + default: + return nil, errors.New("session closed before response completed") + } } // SendPromptAndWait is a convenience wrapper for [Session.SendAndWait] that @@ -595,6 +649,8 @@ func (s *Session) SendPromptAndWait(ctx context.Context, prompt string) (*Sessio // // The returned function can be called to unsubscribe the handler. It is safe // to call the unsubscribe function multiple times. +// Unsubscribing also removes an entry from dispatch snapshots if it has not started. +// Registration after the session closes is logged and returns a no-op unsubscribe. // // Example: // @@ -610,12 +666,28 @@ func (s *Session) SendPromptAndWait(ctx context.Context, prompt string) (*Sessio // // Later, to stop receiving events: // unsubscribe() func (s *Session) On(handler SessionEventHandler) func() { + return s.on(handler, false) +} + +func (s *Session) on(handler SessionEventHandler, prepend bool) func() { s.handlerMutex.Lock() defer s.handlerMutex.Unlock() + select { + case <-s.eventDone: + log.Printf("Cannot register an event handler on closed session %s", s.SessionID) + return func() {} + default: + } + id := s.nextHandlerID s.nextHandlerID++ - s.handlers = append(s.handlers, sessionHandler{id: id, fn: handler}) + entry := &sessionHandler{id: id, fn: handler} + if prepend { + s.handlers = append([]*sessionHandler{entry}, s.handlers...) + } else { + s.handlers = append(s.handlers, entry) + } // Return unsubscribe function return func() { @@ -624,6 +696,7 @@ func (s *Session) On(handler SessionEventHandler) func() { for i, h := range s.handlers { if h.id == id { + h.fn = nil s.handlers = append(s.handlers[:i], s.handlers[i+1:]...) break } @@ -638,7 +711,9 @@ func (s *Session) On(handler SessionEventHandler) func() { // // This method is internal and typically called when creating a session with tools. func (s *Session) registerTools(tools []Tool) { - s.replaceToolHandlers(buildToolHandlerMap(tools)) + if err := s.replaceToolHandlers(buildToolHandlerMap(tools)); err != nil { + log.Printf("Cannot register tools on session %s: %v", s.SessionID, err) + } } func buildToolHandlerMap(tools []Tool) map[string]ToolHandler { @@ -652,10 +727,16 @@ func buildToolHandlerMap(tools []Tool) map[string]ToolHandler { return handlers } -func (s *Session) replaceToolHandlers(handlers map[string]ToolHandler) { +func (s *Session) replaceToolHandlers(handlers map[string]ToolHandler) error { s.toolHandlersM.Lock() defer s.toolHandlersM.Unlock() + select { + case <-s.eventDone: + return errors.New("session closed before tool handlers could be installed") + default: + } s.toolHandlers = handlers + return nil } // getToolHandler retrieves a registered tool handler by name. @@ -727,14 +808,16 @@ func (s *Session) registerExitPlanModeHandler(handler ExitPlanModeRequestHandler s.exitPlanModeHandler = handler } -func (s *Session) getExitPlanModeHandler() ExitPlanModeRequestHandler { - s.exitPlanModeMu.RLock() - defer s.exitPlanModeMu.RUnlock() - return s.exitPlanModeHandler -} - func (s *Session) handleExitPlanModeRequest(request ExitPlanModeRequest) (ExitPlanModeResult, error) { - handler := s.getExitPlanModeHandler() + s.exitPlanModeMu.RLock() + select { + case <-s.eventDone: + s.exitPlanModeMu.RUnlock() + return ExitPlanModeResult{}, errors.New("session closed before exit-plan-mode request") + default: + } + handler := s.exitPlanModeHandler + s.exitPlanModeMu.RUnlock() if handler == nil { return ExitPlanModeResult{Approved: true}, nil } @@ -748,14 +831,16 @@ func (s *Session) registerAutoModeSwitchHandler(handler AutoModeSwitchRequestHan s.autoModeSwitchHandler = handler } -func (s *Session) getAutoModeSwitchHandler() AutoModeSwitchRequestHandler { - s.autoModeSwitchMu.RLock() - defer s.autoModeSwitchMu.RUnlock() - return s.autoModeSwitchHandler -} - func (s *Session) handleAutoModeSwitchRequest(request AutoModeSwitchRequest) (AutoModeSwitchResponse, error) { - handler := s.getAutoModeSwitchHandler() + s.autoModeSwitchMu.RLock() + select { + case <-s.eventDone: + s.autoModeSwitchMu.RUnlock() + return "", errors.New("session closed before auto-mode-switch request") + default: + } + handler := s.autoModeSwitchHandler + s.autoModeSwitchMu.RUnlock() if handler == nil { return AutoModeSwitchResponseNo, nil } @@ -775,17 +860,18 @@ func (s *Session) registerHooks(hooks *SessionHooks) { s.hooks = hooks } -// getHooks returns the currently registered hooks, or nil. -func (s *Session) getHooks() *SessionHooks { - s.hooksMux.RLock() - defer s.hooksMux.RUnlock() - return s.hooks -} - // handleHooksInvoke handles a hook invocation from the Copilot CLI. // This is an internal method called by the SDK when the CLI invokes a hook. func (s *Session) handleHooksInvoke(hookType string, rawInput json.RawMessage) (any, error) { - hooks := s.getHooks() + s.hooksMux.RLock() + select { + case <-s.eventDone: + s.hooksMux.RUnlock() + return nil, errors.New("session closed before hook invocation") + default: + } + hooks := s.hooks + s.hooksMux.RUnlock() if hooks == nil { return nil, nil @@ -948,6 +1034,12 @@ type systemMessageTransformResponse struct { // This is an internal method called by the SDK when the CLI requests section transforms. func (s *Session) handleSystemMessageTransform(sections map[string]systemMessageTransformSection) (systemMessageTransformResponse, error) { s.transformMu.Lock() + select { + case <-s.eventDone: + s.transformMu.Unlock() + return systemMessageTransformResponse{}, errors.New("session closed before system message transform") + default: + } callbacks := s.transformCallbacks s.transformMu.Unlock() @@ -1467,7 +1559,11 @@ func (s *Session) dispatchEvent(event SessionEvent) { broadcastHandled := false switch data := event.Data.(type) { case *ExternalToolRequestedData: - s.startExternalTool(data) + var agentID string + if event.AgentID != nil { + agentID = *event.AgentID + } + s.startExternalTool(data, agentID) broadcastHandled = true case *ExternalToolCompletedData: s.cancelExternalTool(data.RequestID) @@ -1489,6 +1585,12 @@ func (s *Session) dispatchEvent(event SessionEvent) { // others from receiving the event. func (s *Session) processEvents() { for { + select { + case <-s.eventDone: + return + default: + } + var event SessionEvent select { case event = <-s.eventCh: @@ -1497,13 +1599,23 @@ func (s *Session) processEvents() { } s.handlerMutex.RLock() - handlers := make([]SessionEventHandler, 0, len(s.handlers)) - for _, h := range s.handlers { - handlers = append(handlers, h.fn) - } + handlers := append([]*sessionHandler(nil), s.handlers...) s.handlerMutex.RUnlock() - for _, handler := range handlers { + for _, entry := range handlers { + s.handlerMutex.RLock() + select { + case <-s.eventDone: + s.handlerMutex.RUnlock() + return + default: + } + handler := entry.fn + s.handlerMutex.RUnlock() + if handler == nil { + continue + } + func() { defer func() { if r := recover(); r != nil { @@ -1516,11 +1628,77 @@ func (s *Session) processEvents() { } } -// stopEventProcessing stops the session event consumer without making an RPC. +// stopEventProcessing signals the consumer to stop without making an RPC or +// waiting for a user handler that may itself be stopping the client. +// It releases registered callbacks, including unadmitted event snapshot entries. // CreateSession/ResumeSession use this when a locally registered session fails // before it can be returned to the caller. func (s *Session) stopEventProcessing() { - s.closeOnce.Do(func() { close(s.eventDone) }) + s.retireEventProcessing(false) +} + +func (s *Session) retireEventProcessing(graceful bool) { + s.closeOnce.Do(func() { + s.handlerMutex.Lock() + s.gracefulRetirement = graceful + close(s.eventDone) + for _, handler := range s.handlers { + handler.fn = nil + } + s.handlers = nil + s.handlerMutex.Unlock() + + s.clearSkillProvider() + s.releaseGitHubTokenProviderRegistration() + + s.toolHandlersM.Lock() + s.toolHandlers = nil + s.toolHandlersM.Unlock() + + s.permissionMux.Lock() + s.permissionHandler = nil + s.permissionMux.Unlock() + + s.mcpAuthMu.Lock() + s.mcpAuthHandler = nil + s.mcpAuthMu.Unlock() + + s.userInputMux.Lock() + s.userInputHandler = nil + s.userInputMux.Unlock() + + s.exitPlanModeMu.Lock() + s.exitPlanModeHandler = nil + s.exitPlanModeMu.Unlock() + + s.autoModeSwitchMu.Lock() + s.autoModeSwitchHandler = nil + s.autoModeSwitchMu.Unlock() + + s.hooksMux.Lock() + s.hooks = nil + s.hooksMux.Unlock() + + s.transformMu.Lock() + s.transformCallbacks = nil + s.transformMu.Unlock() + + s.commandHandlersMu.Lock() + s.commandHandlers = nil + s.commandHandlersMu.Unlock() + + s.elicitationMu.Lock() + s.elicitationHandler = nil + s.elicitationMu.Unlock() + + s.canvasMu.Lock() + s.canvasHandler = nil + s.canvasMu.Unlock() + + s.bearerTokenMu.Lock() + s.bearerTokenProviders = nil + s.bearerTokenMu.Unlock() + }) } // handleBroadcastEvent handles broadcast request events by executing local handlers @@ -1615,7 +1793,7 @@ func (s *Session) handleBroadcastEvent(event SessionEvent) { } } -func (s *Session) startExternalTool(data *ExternalToolRequestedData) { +func (s *Session) startExternalTool(data *ExternalToolRequestedData, agentID string) { handler, ok := s.getToolHandler(data.ToolName) if !ok { return @@ -1649,7 +1827,7 @@ func (s *Session) startExternalTool(data *ExternalToolRequestedData) { s.pendingExternalTools[data.RequestID] = pending s.pendingExternalToolsM.Unlock() - go s.executeToolAndRespond(data.RequestID, data.ToolName, data.ToolCallID, data.Arguments, handler, pending) + go s.executeToolAndRespond(data.RequestID, data.ToolName, data.ToolCallID, agentID, data.Arguments, handler, pending) } func (s *Session) cancelExternalTool(requestID string) { @@ -1684,7 +1862,7 @@ func (s *Session) claimExternalTool(requestID string, pending *pendingExternalTo } // executeToolAndRespond executes a tool handler and sends the result back via RPC. -func (s *Session) executeToolAndRespond(requestID, toolName, toolCallID string, arguments any, handler ToolHandler, pending *pendingExternalTool) { +func (s *Session) executeToolAndRespond(requestID, toolName, toolCallID, agentID string, arguments any, handler ToolHandler, pending *pendingExternalTool) { ctx := pending.ctx defer func() { s.pendingExternalToolsM.Lock() @@ -1713,6 +1891,8 @@ func (s *Session) executeToolAndRespond(requestID, toolName, toolCallID string, ToolName: toolName, Arguments: arguments, TraceContext: ctx, + AgentID: agentID, + RequestID: requestID, } // The built-in tool-search tool receives a snapshot of the session's @@ -1895,6 +2075,7 @@ func (s *Session) GetEvents(ctx context.Context) ([]SessionEvent, error) { // log.Printf("Failed to disconnect session: %v", err) // } func (s *Session) Disconnect() error { + s.clearSkillProvider() s.cancelPendingExternalTools() result, err := s.client.Request(context.Background(), "session.detach", sessionDetachRequest{SessionID: s.SessionID}) if err == nil { @@ -1912,29 +2093,7 @@ func (s *Session) Disconnect() error { // Local cleanup always runs, even if the detach RPC failed, so callers // don't leak in-memory resources (event goroutines, registered // providers/handlers) just because the runtime couldn't be reached. - s.stopEventProcessing() - s.releaseGitHubTokenProviderRegistration() - - // Clear handlers - s.handlerMutex.Lock() - s.handlers = nil - s.handlerMutex.Unlock() - - s.toolHandlersM.Lock() - s.toolHandlers = nil - s.toolHandlersM.Unlock() - - s.permissionMux.Lock() - s.permissionHandler = nil - s.permissionMux.Unlock() - - s.commandHandlersMu.Lock() - s.commandHandlers = nil - s.commandHandlersMu.Unlock() - - s.elicitationMu.Lock() - s.elicitationHandler = nil - s.elicitationMu.Unlock() + s.retireEventProcessing(true) if err != nil { return fmt.Errorf("failed to disconnect session: %w", err) @@ -2123,7 +2282,7 @@ func toolDefinitionsForSetTools(tools []Tool) []rpc.ProtocolExternalToolDefiniti // not block later calls. If ctx is done before the request is sent, for example // while an earlier SetTools call is still in flight, nothing is sent. Once the // request is sent, ctx only bounds the wait: an accepted replacement still -// installs its handlers. +// installs its handlers unless the session has since closed. // // The agent sees the new tools from its next model request, which can fall // within a turn in progress. A model request already in flight was made with the @@ -2161,8 +2320,7 @@ func (s *Session) SetTools(ctx context.Context, tools []Tool) error { done <- fmt.Errorf("failed to set tools: %w", err) return } - s.replaceToolHandlers(handlers) - done <- nil + done <- s.replaceToolHandlers(handlers) }() select { diff --git a/go/session_retirement_test.go b/go/session_retirement_test.go new file mode 100644 index 0000000000..44c646d261 --- /dev/null +++ b/go/session_retirement_test.go @@ -0,0 +1,364 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package copilot + +import ( + "context" + "fmt" + "strings" + "testing" + "time" +) + +func TestSession_RetirementClearsCallbackRoots(t *testing.T) { + session, cleanup := newTestSession() + t.Cleanup(cleanup) + session.On(func(SessionEvent) {}) + entry := session.handlers[0] + session.registerTools([]Tool{{Name: "tool", Handler: func(ToolInvocation) (ToolResult, error) { return ToolResult{}, nil }}}) + session.registerPermissionHandler(PermissionHandler.ApproveAll) + session.registerMCPAuthHandler(func(MCPAuthRequest, MCPAuthInvocation) (*MCPAuthResult, error) { return nil, nil }) + session.registerUserInputHandler(func(UserInputRequest, UserInputInvocation) (UserInputResponse, error) { + return UserInputResponse{}, nil + }) + session.registerExitPlanModeHandler(func(ExitPlanModeRequest, ExitPlanModeInvocation) (ExitPlanModeResult, error) { + return ExitPlanModeResult{}, nil + }) + session.registerAutoModeSwitchHandler(func(AutoModeSwitchRequest, AutoModeSwitchInvocation) (AutoModeSwitchResponse, error) { + return AutoModeSwitchResponseNo, nil + }) + hooks := &SessionHooks{OnSessionEnd: func(SessionEndHookInput, HookInvocation) (*SessionEndHookOutput, error) { + return nil, nil + }} + session.registerHooks(hooks) + transforms := map[string]SectionTransformFn{"instructions": func(value string) (string, error) { return value, nil }} + session.registerTransformCallbacks(transforms) + session.registerCommands([]CommandDefinition{{Name: "command", Handler: func(CommandContext) error { return nil }}}) + session.registerElicitationHandler(func(ElicitationContext) (ElicitationResult, error) { return ElicitationResult{}, nil }) + session.registerCanvasHandler(&recordingCanvasHandler{}) + session.registerBearerTokenProviders(map[string]BearerTokenProvider{ + "provider": func(ProviderTokenArgs) (string, error) { return "token", nil }, + }) + releases := 0 + session.setGitHubTokenProviderRegistrationRelease(func() { releases++ }) + + session.stopEventProcessing() + session.stopEventProcessing() + + for name, retained := range map[string]bool{ + "event registrations": len(session.handlers) != 0, + "retained event entry": entry.fn != nil, + "tools": session.toolHandlers != nil, + "permissions": session.permissionHandler != nil, + "MCP auth": session.mcpAuthHandler != nil, + "user input": session.userInputHandler != nil, + "exit plan mode": session.exitPlanModeHandler != nil, + "auto mode switch": session.autoModeSwitchHandler != nil, + "hooks": session.hooks != nil, + "transforms": session.transformCallbacks != nil, + "commands": session.commandHandlers != nil, + "elicitation": session.elicitationHandler != nil, + "canvas": session.canvasHandler != nil, + "bearer token": session.bearerTokenProviders != nil, + "provider release": session.releaseGitHubTokenProvider != nil, + } { + if retained { + t.Errorf("retired session retained %s", name) + } + } + if releases != 1 { + t.Errorf("provider releases = %d, want exactly one", releases) + } + if hooks.OnSessionEnd == nil || transforms["instructions"] == nil { + t.Fatal("retirement mutated caller-owned hook or transform configuration") + } +} + +func TestSession_RetirementRejectsCallbackRebinding(t *testing.T) { + session, cleanup := newTestSession() + t.Cleanup(cleanup) + session.stopEventProcessing() + unsubscribe := session.On(func(SessionEvent) {}) + if len(session.handlers) != 0 { + t.Fatal("retired session accepted a late event registration") + } + unsubscribe() + unsubscribe() + session.registerTools([]Tool{{Name: "late", Handler: func(ToolInvocation) (ToolResult, error) { return ToolResult{}, nil }}}) + if session.toolHandlers != nil { + t.Fatal("retired session retained late tool handlers") + } +} + +func TestSession_RetirementRejectsEmptyCallbackSuccess(t *testing.T) { + t.Run("hooks", func(t *testing.T) { + session, cleanup := newTestSession() + t.Cleanup(cleanup) + session.SessionID = "retirement-session" + client := &Client{sessions: map[string]*Session{session.SessionID: session}} + request := hooksInvokeRequest{SessionID: session.SessionID, Type: "preToolUse", Input: []byte("{}")} + if _, err := client.handleHooksInvoke(request); err != nil { + t.Fatalf("live session without hooks returned an error: %v", err) + } + session.stopEventProcessing() + _, err := client.handleHooksInvoke(request) + if err == nil || err.Code != -32603 || !strings.Contains(err.Message, "session closed") { + t.Fatalf("retired hook request error = %+v, want closed-session RPC error", err) + } + }) + t.Run("system message transforms", func(t *testing.T) { + session, cleanup := newTestSession() + t.Cleanup(cleanup) + sections := map[string]systemMessageTransformSection{"instructions": {Content: "keep this policy"}} + response, err := session.handleSystemMessageTransform(sections) + if err != nil || response.Sections["instructions"].Content != "keep this policy" { + t.Fatalf("live session without transforms changed content: %+v, %v", response, err) + } + session.stopEventProcessing() + response, err = session.handleSystemMessageTransform(sections) + if err == nil || !strings.Contains(err.Error(), "session closed") { + t.Fatalf("retired transform response = %+v, %v; want closed error", response, err) + } + }) +} + +func TestSession_RetirementRejectsModeRequestDefaults(t *testing.T) { + t.Run("exit plan mode", func(t *testing.T) { + session, cleanup := newTestSession() + t.Cleanup(cleanup) + session.stopEventProcessing() + response, err := session.handleExitPlanModeRequest(ExitPlanModeRequest{}) + if err == nil || !strings.Contains(err.Error(), "session closed") || response.Approved { + t.Fatalf("retired exit-plan-mode response = %+v, %v; want closed error without approval", response, err) + } + }) + t.Run("auto mode switch", func(t *testing.T) { + session, cleanup := newTestSession() + t.Cleanup(cleanup) + session.stopEventProcessing() + response, err := session.handleAutoModeSwitchRequest(AutoModeSwitchRequest{}) + if err == nil || !strings.Contains(err.Error(), "session closed") { + t.Fatalf("retired auto-mode-switch response = %+v, %v; want closed error", response, err) + } + }) +} + +func TestSession_SetToolsAcceptedAfterRetirementDoesNotRebind(t *testing.T) { + session, server := newSetToolsTestSession(t) + session.eventDone = make(chan struct{}) + session.eventCh = make(chan SessionEvent, 2) + processingDone := make(chan struct{}) + go func() { + defer close(processingDone) + session.processEvents() + }() + t.Cleanup(func() { + session.stopEventProcessing() + select { + case <-processingDone: + case <-time.After(2 * time.Second): + t.Error("event processing did not stop after retirement") + } + }) + result := make(chan error, 1) + go func() { + result <- session.SetTools(context.Background(), []Tool{{ + Name: "late", Handler: func(ToolInvocation) (ToolResult, error) { return ToolResult{}, nil }, + }}) + }() + request := server.expectRequest(t, "session.tools.set") + // Keep the transport alive so an accepted late ACK cannot mask local retirement. + session.stopEventProcessing() + server.respond(t, request.ID, map[string]any{}) + err := awaitSetTools(t, result) + if err == nil || !strings.Contains(err.Error(), "session closed") { + t.Fatalf("SetTools error = %v, want session closed", err) + } + + if _, ok := session.getToolHandler("late"); ok { + t.Fatal("accepted late replacement resurrected retired tool handlers") + } +} + +func TestSession_SendAndWaitPreservesTerminalResultBeforeRetirement(t *testing.T) { + for _, terminal := range []string{"idle", "error", "missing", "error-then-idle", "idle-then-error"} { + for iteration := range 32 { + t.Run(fmt.Sprintf("%s-%d", terminal, iteration), func(t *testing.T) { + session, server := newSetToolsTestSession(t) + session.eventDone = make(chan struct{}) + session.eventCh = make(chan SessionEvent, 2) + processingDone := make(chan struct{}) + go func() { + defer close(processingDone) + session.processEvents() + }() + t.Cleanup(func() { + session.stopEventProcessing() + select { + case <-processingDone: + case <-time.After(2 * time.Second): + t.Error("event processing did not stop after retirement") + } + }) + type response struct { + event *SessionEvent + err error + } + result := make(chan response, 1) + go func() { + event, err := session.SendAndWait(context.Background(), MessageOptions{Prompt: "finish"}) + result <- response{event: event, err: err} + }() + request := server.expectRequest(t, "session.send") + terminalObserved := make(chan struct{}, 2) + unsubscribe := session.On(func(event SessionEvent) { + switch event.Data.(type) { + case *SessionIdleData, *SessionErrorData: + terminalObserved <- struct{}{} + } + }) + defer unsubscribe() + switch terminal { + case "idle", "idle-then-error": + session.dispatchEvent(SessionEvent{Data: &AssistantMessageData{Content: "finished"}}) + session.dispatchEvent(SessionEvent{Data: &SessionIdleData{}}) + if terminal == "idle-then-error" { + session.dispatchEvent(SessionEvent{Data: &SessionErrorData{Message: "later provider failure"}}) + } + case "error", "error-then-idle": + session.dispatchEvent(SessionEvent{Data: &SessionErrorData{Message: "provider failed"}}) + if terminal == "error-then-idle" { + session.dispatchEvent(SessionEvent{Data: &SessionIdleData{}}) + } + } + if terminal != "missing" { + count := 1 + if terminal == "error-then-idle" || terminal == "idle-then-error" { + count = 2 + } + for range count { + select { + case <-terminalObserved: + case <-time.After(2 * time.Second): + t.Fatal("the wait did not receive its terminal event before retirement") + } + } + } + // Publish retirement before the send ACK so it can race the terminal result. + session.stopEventProcessing() + server.respond(t, request.ID, map[string]any{"messageId": "message-1"}) + select { + case response := <-result: + switch terminal { + case "idle", "idle-then-error": + if response.err != nil || response.event == nil { + t.Fatalf("completed response = %+v, %v; want assistant message", response.event, response.err) + } + message, ok := response.event.Data.(*AssistantMessageData) + if !ok || message.Content != "finished" { + t.Fatalf("assistant response = %+v, want finished", response.event.Data) + } + case "error", "error-then-idle": + if response.err == nil || response.err.Error() != "session error: provider failed" { + t.Fatalf("terminal error = %v, want provider failure", response.err) + } + case "missing": + if response.err == nil || response.err.Error() != "session closed before response completed" { + t.Fatalf("incomplete response error = %v, want session closure", response.err) + } + } + case <-time.After(2 * time.Second): + t.Fatal("SendAndWait did not observe the acknowledged send and retirement") + } + }) + } + } +} + +func TestSession_SendAndWaitPreservesTerminalResultWhenHandlerDisconnects(t *testing.T) { + for _, terminal := range []string{"idle", "error"} { + t.Run(terminal, func(t *testing.T) { + t.Parallel() + session, server := newSetToolsTestSession(t) + session.eventDone = make(chan struct{}) + session.eventCh = make(chan SessionEvent, 2) + processingDone := make(chan struct{}) + go func() { + defer close(processingDone) + session.processEvents() + }() + t.Cleanup(func() { + session.stopEventProcessing() + select { + case <-processingDone: + case <-time.After(2 * time.Second): + t.Error("event processing did not stop after retirement") + } + }) + + disconnected := make(chan error, 1) + session.On(func(event SessionEvent) { + switch event.Data.(type) { + case *SessionIdleData, *SessionErrorData: + disconnected <- session.Disconnect() + } + }) + lateCallback := make(chan struct{}, 1) + session.On(func(event SessionEvent) { + switch event.Data.(type) { + case *SessionIdleData, *SessionErrorData: + lateCallback <- struct{}{} + } + }) + type response struct { + event *SessionEvent + err error + } + result := make(chan response, 1) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) + defer cancel() + go func() { + event, err := session.SendAndWait(ctx, MessageOptions{Prompt: "finish"}) + result <- response{event: event, err: err} + }() + send := server.expectRequest(t, "session.send") + session.dispatchEvent(SessionEvent{Data: &AssistantMessageData{Content: "finished"}}) + if terminal == "idle" { + session.dispatchEvent(SessionEvent{Data: &SessionIdleData{}}) + } else { + session.dispatchEvent(SessionEvent{Data: &SessionErrorData{Message: "provider failed"}}) + } + detach := server.expectRequest(t, "session.detach") + server.respond(t, detach.ID, map[string]any{"success": true}) + select { + case err := <-disconnected: + if err != nil { + t.Fatal("disconnect:", err) + } + case <-ctx.Done(): + t.Fatal("terminal handler did not disconnect") + } + select { + case <-lateCallback: + t.Fatal("retirement admitted a later user callback from the same event snapshot") + default: + } + // Acknowledge only after the earlier handler has retired the session. + server.respond(t, send.ID, map[string]any{"messageId": "message-1"}) + select { + case response := <-result: + if terminal == "error" { + if response.err == nil || response.err.Error() != "session error: provider failed" { + t.Fatalf("terminal error = %v, want provider failure", response.err) + } + } else if response.err != nil || response.event == nil { + t.Fatalf("completed response = %+v, %v; want assistant message", response.event, response.err) + } else if message, ok := response.event.Data.(*AssistantMessageData); !ok || message.Content != "finished" { + t.Fatalf("assistant response = %+v, want finished", response.event.Data) + } + case <-ctx.Done(): + t.Fatal("SendAndWait did not preserve the terminal result") + } + }) + } +} diff --git a/go/session_test.go b/go/session_test.go index b66643544b..38a365fbd6 100644 --- a/go/session_test.go +++ b/go/session_test.go @@ -22,7 +22,7 @@ import ( // Returns a cleanup function that stops the consumer. func newTestSession() (*Session, func()) { s := &Session{ - handlers: make([]sessionHandler, 0), + handlers: make([]*sessionHandler, 0), commandHandlers: make(map[string]CommandHandler), eventCh: make(chan SessionEvent, 128), eventDone: make(chan struct{}), @@ -71,6 +71,68 @@ func TestExternalToolCompletedCancelsBlockedHandler(t *testing.T) { } } +func TestToolInvocationNamesTheSubAgentAndRequestBehindTheCall(t *testing.T) { + session, cleanup := newTestSession() + defer cleanup() + + invocations := make(chan ToolInvocation, 3) + session.registerTools([]Tool{{ + Name: "calc", + Handler: func(invocation ToolInvocation) (ToolResult, error) { + invocations <- invocation + <-invocation.TraceContext.Done() + return ToolResult{}, invocation.TraceContext.Err() + }, + }}) + + session.dispatchEvent(SessionEvent{ + AgentID: ptr("task-agent-1"), + Data: &ExternalToolRequestedData{ + RequestID: "req-sub-agent", + SessionID: "session-1", + ToolCallID: "tc-sub-agent", + ToolName: "calc", + }, + }) + defer session.dispatchEvent(SessionEvent{Data: &ExternalToolCompletedData{RequestID: "req-sub-agent"}}) + session.dispatchEvent(SessionEvent{Data: &ExternalToolRequestedData{ + RequestID: "req-root", + SessionID: "session-1", + ToolCallID: "tc-root", + ToolName: "calc", + }}) + defer session.dispatchEvent(SessionEvent{Data: &ExternalToolCompletedData{RequestID: "req-root"}}) + session.dispatchEvent(SessionEvent{ + AgentID: ptr(""), + Data: &ExternalToolRequestedData{ + RequestID: "req-blank-agent", + SessionID: "session-1", + ToolCallID: "tc-blank-agent", + ToolName: "calc", + }, + }) + defer session.dispatchEvent(SessionEvent{Data: &ExternalToolCompletedData{RequestID: "req-blank-agent"}}) + + got := make(map[string]ToolInvocation) + for range 3 { + select { + case invocation := <-invocations: + got[invocation.ToolCallID] = invocation + case <-time.After(time.Second): + t.Fatal("tool handler did not start") + } + } + if sub := got["tc-sub-agent"]; sub.AgentID != "task-agent-1" || sub.RequestID != "req-sub-agent" { + t.Fatalf("sub-agent call: got AgentID %q RequestID %q", sub.AgentID, sub.RequestID) + } + if root := got["tc-root"]; root.AgentID != "" || root.RequestID != "req-root" { + t.Fatalf("root call: got AgentID %q RequestID %q", root.AgentID, root.RequestID) + } + if blank := got["tc-blank-agent"]; blank.AgentID != "" || blank.RequestID != "req-blank-agent" { + t.Fatalf("blank-agent call: got AgentID %q RequestID %q", blank.AgentID, blank.RequestID) + } +} + func TestDispatchEventReturnsAfterEventProcessingStops(t *testing.T) { session := &Session{ eventCh: make(chan SessionEvent), @@ -314,7 +376,7 @@ func TestSession_SetToolsRunningCallsFinishOnOriginalHandler(t *testing.T) { SessionID: "session-1", ToolCallID: "tool-call-1", ToolName: "lookup", - }) + }, "") select { case <-started: case <-time.After(2 * time.Second): @@ -1064,7 +1126,7 @@ func checkSendAndWaitSkipsSubagentAndAutopilotContinuationIdle(t *testing.T, roo SessionID: "session-1", client: client, RPC: rpc.NewSessionRPC(client, "session-1"), - handlers: make([]sessionHandler, 0), + handlers: make([]*sessionHandler, 0), eventCh: make(chan SessionEvent, 8), eventDone: make(chan struct{}), } diff --git a/go/skill_provider_test.go b/go/skill_provider_test.go new file mode 100644 index 0000000000..957b99aa8f --- /dev/null +++ b/go/skill_provider_test.go @@ -0,0 +1,700 @@ +package copilot + +import ( + "context" + "encoding/json" + "errors" + "log" + "strings" + "sync" + "testing" + + "github.com/github/copilot-sdk/go/internal/jsonrpc2" + "github.com/github/copilot-sdk/go/rpc" +) + +type testSkillProvider struct { + mu sync.Mutex + skills []rpc.SkillProviderDescriptor + markdown map[string]string + listErr error + readErr error + calls []string +} + +func (p *testSkillProvider) ListSkills(context.Context) ([]rpc.SkillProviderDescriptor, error) { + p.mu.Lock() + defer p.mu.Unlock() + p.calls = append(p.calls, "list") + if p.listErr != nil { + return nil, p.listErr + } + return p.skills, nil +} + +func (p *testSkillProvider) ReadSkill(_ context.Context, name string) (string, error) { + p.mu.Lock() + defer p.mu.Unlock() + p.calls = append(p.calls, "read:"+name) + if p.readErr != nil { + return "", p.readErr + } + markdown, ok := p.markdown[name] + if !ok { + return "", ErrSkillNotFound + } + return markdown, nil +} + +func (p *testSkillProvider) snapshotCalls() []string { + p.mu.Lock() + defer p.mu.Unlock() + return append([]string(nil), p.calls...) +} + +var reviewSkillDescriptor = rpc.SkillProviderDescriptor{ + Name: "review", + Description: "Reviews code", +} + +func newTestSkillProvider() *testSkillProvider { + return &testSkillProvider{ + skills: []rpc.SkillProviderDescriptor{reviewSkillDescriptor}, + markdown: map[string]string{"review": "Review carefully."}, + } +} + +func TestSkillProviderSessionPayloads(t *testing.T) { + t.Run("omits flag without provider and sends flag with provider", func(t *testing.T) { + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + + createParams := make(chan json.RawMessage, 2) + resumeParams := make(chan json.RawMessage, 2) + server.SetRequestHandler("session.create", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + createParams <- append(json.RawMessage(nil), params...) + sessionID := sessionIDFromParams(t, params) + return []byte(`{"sessionId":"` + sessionID + `","workspacePath":"/workspace"}`), nil + }) + server.SetRequestHandler("session.resume", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + resumeParams <- append(json.RawMessage(nil), params...) + sessionID := sessionIDFromParams(t, params) + return []byte(`{"sessionId":"` + sessionID + `","workspacePath":"/workspace"}`), nil + }) + + if _, err := client.CreateSession(t.Context(), &SessionConfig{}); err != nil { + t.Fatalf("CreateSession without provider failed: %v", err) + } + if _, err := client.ResumeSession(t.Context(), "resume-without-provider", &ResumeSessionConfig{}); err != nil { + t.Fatalf("ResumeSession without provider failed: %v", err) + } + provider := newTestSkillProvider() + if _, err := client.CreateSession(t.Context(), &SessionConfig{SkillProvider: provider}); err != nil { + t.Fatalf("CreateSession with provider failed: %v", err) + } + if _, err := client.ResumeSession(t.Context(), "resume-with-provider", &ResumeSessionConfig{SkillProvider: provider}); err != nil { + t.Fatalf("ResumeSession with provider failed: %v", err) + } + + assertSkillProviderFlag(t, <-createParams, false) + assertSkillProviderFlag(t, <-resumeParams, false) + assertSkillProviderFlag(t, <-createParams, true) + assertSkillProviderFlag(t, <-resumeParams, true) + if got := provider.snapshotCalls(); len(got) != 0 { + t.Fatalf("provider was called during open: %v", got) + } + }) + + t.Run("keeps empty mode enableSkills default with provider", func(t *testing.T) { + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + options: ClientOptions{Mode: ModeEmpty}, + } + + createParams := make(chan json.RawMessage, 1) + server.SetRequestHandler("session.create", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + createParams <- append(json.RawMessage(nil), params...) + sessionID := sessionIDFromParams(t, params) + return []byte(`{"sessionId":"` + sessionID + `"}`), nil + }) + server.SetRequestHandler("session.options.update", func(json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + return []byte(`{}`), nil + }) + + if _, err := client.CreateSession(t.Context(), &SessionConfig{ + AvailableTools: []string{}, + SkillProvider: newTestSkillProvider(), + }); err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + var payload map[string]any + if err := json.Unmarshal(<-createParams, &payload); err != nil { + t.Fatal(err) + } + if payload["enableSkills"] != false { + t.Fatalf("enableSkills = %v, want false", payload["enableSkills"]) + } + if payload["hasSkillProvider"] != true { + t.Fatalf("hasSkillProvider = %v, want true", payload["hasSkillProvider"]) + } + }) +} + +func TestSkillProviderServesEarlyCallbacksDuringOpen(t *testing.T) { + for _, method := range []string{"session.create", "session.resume"} { + t.Run(method, func(t *testing.T) { + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + client.setupNotificationHandler() + + earlyResult := make(chan rpc.SkillProviderListResult, 1) + server.SetRequestHandler(method, func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + sessionID := sessionIDFromParams(t, params) + raw, err := server.Request(t.Context(), "skillProvider.list", map[string]any{"sessionId": sessionID}) + if err != nil { + if rpcErr, ok := err.(*jsonrpc2.Error); ok { + return nil, rpcErr + } + return nil, &jsonrpc2.Error{Code: -32603, Message: err.Error()} + } + var result rpc.SkillProviderListResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: err.Error()} + } + earlyResult <- result + return []byte(`{"sessionId":"` + sessionID + `"}`), nil + }) + + provider := newTestSkillProvider() + if method == "session.create" { + if _, err := client.CreateSession(t.Context(), &SessionConfig{SkillProvider: provider}); err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + } else if _, err := client.ResumeSession(t.Context(), "early-resume", &ResumeSessionConfig{SkillProvider: provider}); err != nil { + t.Fatalf("ResumeSession failed: %v", err) + } + + got := <-earlyResult + if len(got.Skills) != 1 || got.Skills[0].Name != "review" { + t.Fatalf("early list result = %+v", got) + } + }) + } +} + +func TestSkillProviderRejectsCloudBeforeConnect(t *testing.T) { + provider := newTestSkillProvider() + client := &Client{} + + _, err := client.CreateSession(t.Context(), &SessionConfig{ + Cloud: &CloudSessionOptions{}, + SkillProvider: provider, + }) + + if err == nil || err.Error() != "Skill providers are not supported for cloud sessions." { + t.Fatalf("CreateSession error = %v", err) + } + if client.client != nil { + t.Fatal("client connected before rejecting cloud skill provider") + } + if got := provider.snapshotCalls(); len(got) != 0 { + t.Fatalf("provider was called: %v", got) + } +} + +func TestSkillProviderDispatch(t *testing.T) { + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + client.setupNotificationHandler() + + provider := &testSkillProvider{ + skills: []rpc.SkillProviderDescriptor{ + reviewSkillDescriptor, + { + Name: "deploy", + Description: "Deploys the service", + UserInvocable: Bool(false), + DisableModelInvocation: Bool(true), + ArgumentHint: String("[environment]"), + }, + }, + markdown: map[string]string{"deploy": "# deploy"}, + } + session := newSession("dispatch-session", rpcClient, "", false) + session.registerSkillProvider(provider) + client.sessions[session.SessionID] = session + + listRaw, rpcErr := server.Request(t.Context(), "skillProvider.list", map[string]any{"sessionId": session.SessionID}) + if rpcErr != nil { + t.Fatalf("skillProvider.list failed: %v", rpcErr) + } + var listResult rpc.SkillProviderListResult + if err := json.Unmarshal(listRaw, &listResult); err != nil { + t.Fatal(err) + } + if len(listResult.Skills) != 2 || listResult.Skills[1].Name != "deploy" { + t.Fatalf("list result = %+v", listResult) + } + + readRaw, rpcErr := server.Request(t.Context(), "skillProvider.read", map[string]any{ + "sessionId": session.SessionID, + "name": "deploy", + }) + if rpcErr != nil { + t.Fatalf("skillProvider.read failed: %v", rpcErr) + } + var readResult rpc.SkillProviderReadResult + if err := json.Unmarshal(readRaw, &readResult); err != nil { + t.Fatal(err) + } + if readResult.Markdown == nil { + t.Fatal("markdown = nil, want # deploy") + } + if *readResult.Markdown != "# deploy" { + t.Fatalf("markdown = %q, want # deploy", *readResult.Markdown) + } + if got := provider.snapshotCalls(); strings.Join(got, ",") != "list,read:deploy" { + t.Fatalf("provider calls = %v", got) + } +} + +func TestSkillProviderOmitsUnsetOptionalDescriptorFields(t *testing.T) { + data, err := json.Marshal(rpc.SkillProviderListResult{ + Skills: []rpc.SkillProviderDescriptor{{Name: "review", Description: "Reviews code"}}, + }) + if err != nil { + t.Fatal(err) + } + var decoded map[string][]map[string]any + if err := json.Unmarshal(data, &decoded); err != nil { + t.Fatal(err) + } + skill := decoded["skills"][0] + for _, key := range []string{"argumentHint", "userInvocable", "disableModelInvocation"} { + if _, ok := skill[key]; ok { + t.Fatalf("%s should be omitted when unset: %s", key, data) + } + } +} + +func TestSkillProviderEmptyListBecomesEmptyArray(t *testing.T) { + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + client.setupNotificationHandler() + session := newSession("empty-list-session", rpcClient, "", false) + session.registerSkillProvider(&testSkillProvider{}) + client.sessions[session.SessionID] = session + + raw, rpcErr := server.Request(t.Context(), "skillProvider.list", map[string]any{"sessionId": session.SessionID}) + if rpcErr != nil { + t.Fatalf("skillProvider.list failed: %v", rpcErr) + } + if string(raw) != `{"skills":[]}` { + t.Fatalf("list response = %s, want empty skills array", raw) + } +} + +func TestSkillProviderErrorEnvelopes(t *testing.T) { + t.Run("read not found returns null markdown", func(t *testing.T) { + _, server, sessionID := skillProviderErrorHarness(t, newTestSkillProvider()) + raw, rpcErr := server.Request(t.Context(), "skillProvider.read", map[string]any{ + "sessionId": sessionID, + "name": "missing", + }) + if rpcErr != nil { + t.Fatalf("skillProvider.read failed: %v", rpcErr) + } + if string(raw) != `{"markdown":null}` { + t.Fatalf("read response = %s, want null markdown", raw) + } + var result rpc.SkillProviderReadResult + if err := json.Unmarshal(raw, &result); err != nil { + t.Fatal(err) + } + if result.Markdown != nil { + t.Fatalf("markdown = %q, want nil", *result.Markdown) + } + }) + + for _, method := range []string{"skillProvider.list", "skillProvider.read"} { + t.Run(method+" provider failure", func(t *testing.T) { + output := captureSkillProviderLog(t) + secret := errors.New("db-password-in-error") + provider := newTestSkillProvider() + operation := "listSkills" + if method == "skillProvider.list" { + provider.listErr = secret + } else { + provider.readErr = secret + operation = "readSkill" + } + _, server, sessionID := skillProviderErrorHarness(t, provider) + params := map[string]any{"sessionId": sessionID} + wantMessage := "Skill provider " + operation + " failed" + if method == "skillProvider.read" { + params["name"] = "review" + } + + rpcErr := requestSkillProviderError(t, server, method, params) + if rpcErr.Code != -32603 || rpcErr.Message != wantMessage { + t.Fatalf("error = %+v, want generic message %q", rpcErr, wantMessage) + } + if rpcErr.Data != nil { + t.Fatalf("generic provider error data = %s, want omitted", rpcErr.Data) + } + if strings.Contains(rpcErr.Message, secret.Error()) { + t.Fatalf("provider error leaked secret: %q", rpcErr.Message) + } + wantLog := "skill provider " + operation + " failed: session_id=" + sessionID + " error=" + secret.Error() + if got := output.text(); !strings.Contains(got, wantLog) { + t.Fatalf("log = %q, want it to contain %q", got, wantLog) + } + }) + } + + t.Run("not-found classification panic", func(t *testing.T) { + captureSkillProviderLog(t) + provider := newTestSkillProvider() + provider.readErr = panickyIsError{} + _, server, sessionID := skillProviderErrorHarness(t, provider) + + rpcErr := requestSkillProviderError(t, server, "skillProvider.read", map[string]any{ + "sessionId": sessionID, + "name": "review", + }) + if rpcErr.Code != -32603 || rpcErr.Message != "Skill provider readSkill failed" || rpcErr.Data != nil { + t.Fatalf("error = %+v, want generic readSkill failure", rpcErr) + } + }) + + t.Run("unknown session", func(t *testing.T) { + _, server, _ := skillProviderErrorHarness(t, newTestSkillProvider()) + rpcErr := requestSkillProviderError(t, server, "skillProvider.list", map[string]any{"sessionId": "missing"}) + assertSkillProviderError(t, rpcErr, "No skill provider for session: missing") + }) + + for _, method := range []string{"skillProvider.list", "skillProvider.read"} { + t.Run(method+" provider panic", func(t *testing.T) { + output := captureSkillProviderLog(t) + _, server, sessionID := skillProviderErrorHarness(t, panickingSkillProvider{}) + params := map[string]any{"sessionId": sessionID} + wantMessage := "Skill provider listSkills failed" + if method == "skillProvider.read" { + params["name"] = "review" + wantMessage = "Skill provider readSkill failed" + } + + rpcErr := requestSkillProviderError(t, server, method, params) + if rpcErr.Code != -32603 || rpcErr.Message != wantMessage || rpcErr.Data != nil { + t.Fatalf("error = %+v, want generic message %q without data", rpcErr, wantMessage) + } + if got := output.text(); !strings.Contains(got, "panic=db-password-in-panic") { + t.Fatalf("log = %q, want the recovered panic value", got) + } + }) + } + + t.Run("no provider", func(t *testing.T) { + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + client.setupNotificationHandler() + session := newSession("no-provider-session", rpcClient, "", false) + client.sessions[session.SessionID] = session + + rpcErr := requestSkillProviderError(t, server, "skillProvider.read", map[string]any{ + "sessionId": session.SessionID, + "name": "review", + }) + assertSkillProviderError(t, rpcErr, "No skill provider for session: no-provider-session") + }) +} + +func TestSkillProviderTeardown(t *testing.T) { + t.Run("disconnect clears provider", func(t *testing.T) { + client, server, provider, session := newSkillProviderOpenSession(t, "disconnect-session") + + if err := session.Disconnect(); err != nil { + t.Fatalf("Disconnect failed: %v", err) + } + rpcErr := requestSkillProviderError(t, server, "skillProvider.list", map[string]any{"sessionId": session.SessionID}) + assertSkillProviderError(t, rpcErr, "No skill provider for session: disconnect-session") + if got := provider.snapshotCalls(); len(got) != 0 { + t.Fatalf("provider was called after disconnect: %v", got) + } + _ = client + }) + + t.Run("delete clears provider", func(t *testing.T) { + client, server, provider, session := newSkillProviderOpenSession(t, "delete-session") + server.SetRequestHandler("session.delete", func(json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + return []byte(`{"success":true}`), nil + }) + + if err := client.DeleteSession(t.Context(), session.SessionID); err != nil { + t.Fatalf("DeleteSession failed: %v", err) + } + rpcErr := requestSkillProviderError(t, server, "skillProvider.list", map[string]any{"sessionId": session.SessionID}) + assertSkillProviderError(t, rpcErr, "No skill provider for session: delete-session") + if got := provider.snapshotCalls(); len(got) != 0 { + t.Fatalf("provider was called after delete: %v", got) + } + }) + + t.Run("connection loss clears provider", func(t *testing.T) { + client, server, provider, session := newSkillProviderOpenSession(t, "closed-session") + + client.handleConnectionClose() + rpcErr := requestSkillProviderError(t, server, "skillProvider.list", map[string]any{"sessionId": session.SessionID}) + assertSkillProviderError(t, rpcErr, "No skill provider for session: closed-session") + if got := provider.snapshotCalls(); len(got) != 0 { + t.Fatalf("provider was called after connection loss: %v", got) + } + }) + + t.Run("failed create cleanup", func(t *testing.T) { + provider := newTestSkillProvider() + var sessionID string + client, server := newSkillProviderClient(t) + server.SetRequestHandler("session.create", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + sessionID = sessionIDFromParams(t, params) + return nil, &jsonrpc2.Error{Code: -32000, Message: "create failed"} + }) + + if _, err := client.CreateSession(t.Context(), &SessionConfig{SkillProvider: provider}); err == nil { + t.Fatal("CreateSession succeeded unexpectedly") + } + rpcErr := requestSkillProviderError(t, server, "skillProvider.list", map[string]any{"sessionId": sessionID}) + assertSkillProviderError(t, rpcErr, "No skill provider for session: "+sessionID) + if got := provider.snapshotCalls(); len(got) != 0 { + t.Fatalf("provider was called after failed create: %v", got) + } + }) + + t.Run("failed resume cleanup", func(t *testing.T) { + provider := newTestSkillProvider() + client, server := newSkillProviderClient(t) + server.SetRequestHandler("session.resume", func(json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + return nil, &jsonrpc2.Error{Code: -32000, Message: "resume failed"} + }) + + if _, err := client.ResumeSession(t.Context(), "failed-resume", &ResumeSessionConfig{SkillProvider: provider}); err == nil { + t.Fatal("ResumeSession succeeded unexpectedly") + } + rpcErr := requestSkillProviderError(t, server, "skillProvider.list", map[string]any{"sessionId": "failed-resume"}) + assertSkillProviderError(t, rpcErr, "No skill provider for session: failed-resume") + if got := provider.snapshotCalls(); len(got) != 0 { + t.Fatalf("provider was called after failed resume: %v", got) + } + }) +} + +func TestSkillProviderResumeRebinding(t *testing.T) { + t.Run("serves replacement provider", func(t *testing.T) { + client, server := newSkillProviderClient(t) + server.SetRequestHandler("session.create", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + sessionID := sessionIDFromParams(t, params) + return []byte(`{"sessionId":"` + sessionID + `"}`), nil + }) + server.SetRequestHandler("session.resume", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + sessionID := sessionIDFromParams(t, params) + return []byte(`{"sessionId":"` + sessionID + `"}`), nil + }) + original := newTestSkillProvider() + replacement := newTestSkillProvider() + replacement.markdown = map[string]string{"review": "replacement"} + + session, err := client.CreateSession(t.Context(), &SessionConfig{ + SessionID: "rebind-session", + SkillProvider: original, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + if _, err := client.ResumeSession(t.Context(), session.SessionID, &ResumeSessionConfig{SkillProvider: replacement}); err != nil { + t.Fatalf("ResumeSession failed: %v", err) + } + raw, rpcErr := server.Request(t.Context(), "skillProvider.read", map[string]any{ + "sessionId": session.SessionID, + "name": "review", + }) + if rpcErr != nil { + t.Fatalf("skillProvider.read failed: %v", rpcErr) + } + var result rpc.SkillProviderReadResult + if err := json.Unmarshal(raw, &result); err != nil { + t.Fatal(err) + } + if result.Markdown == nil { + t.Fatal("markdown = nil, want replacement") + } + if *result.Markdown != "replacement" { + t.Fatalf("markdown = %q, want replacement", *result.Markdown) + } + if got := original.snapshotCalls(); len(got) != 0 { + t.Fatalf("original provider was called after resume: %v", got) + } + if got := replacement.snapshotCalls(); strings.Join(got, ",") != "read:review" { + t.Fatalf("replacement provider calls = %v", got) + } + }) + + t.Run("resume without provider unbinds previous provider", func(t *testing.T) { + client, server, original, session := newSkillProviderOpenSession(t, "unbind-session") + server.SetRequestHandler("session.resume", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + sessionID := sessionIDFromParams(t, params) + return []byte(`{"sessionId":"` + sessionID + `"}`), nil + }) + + if _, err := client.ResumeSession(t.Context(), session.SessionID, &ResumeSessionConfig{}); err != nil { + t.Fatalf("ResumeSession failed: %v", err) + } + rpcErr := requestSkillProviderError(t, server, "skillProvider.list", map[string]any{"sessionId": session.SessionID}) + assertSkillProviderError(t, rpcErr, "No skill provider for session: unbind-session") + if got := original.snapshotCalls(); len(got) != 0 { + t.Fatalf("original provider was called after unbound resume: %v", got) + } + }) +} + +type panickingSkillProvider struct{} + +func (panickingSkillProvider) ListSkills(context.Context) ([]rpc.SkillProviderDescriptor, error) { + panic("db-password-in-panic") +} + +func (panickingSkillProvider) ReadSkill(context.Context, string) (string, error) { + panic("db-password-in-panic") +} + +// panickyIsError panics when errors.Is asks whether it matches a target. +type panickyIsError struct{} + +func (panickyIsError) Error() string { return "panicky" } + +func (panickyIsError) Is(error) bool { panic("classification panicked") } + +func captureSkillProviderLog(t *testing.T) *ahpTestLog { + t.Helper() + output := new(ahpTestLog) + previous := log.Writer() + log.SetOutput(output) + t.Cleanup(func() { log.SetOutput(previous) }) + return output +} + +func newSkillProviderClient(t *testing.T) (*Client, *jsonrpc2.Client) { + t.Helper() + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + client.setupNotificationHandler() + return client, server +} + +func newSkillProviderOpenSession(t *testing.T, sessionID string) (*Client, *jsonrpc2.Client, *testSkillProvider, *Session) { + t.Helper() + client, server := newSkillProviderClient(t) + provider := newTestSkillProvider() + server.SetRequestHandler("session.create", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + gotSessionID := sessionIDFromParams(t, params) + return []byte(`{"sessionId":"` + gotSessionID + `"}`), nil + }) + server.SetRequestHandler("session.detach", func(json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + return []byte(`{"success":true}`), nil + }) + + session, err := client.CreateSession(t.Context(), &SessionConfig{ + SessionID: sessionID, + SkillProvider: provider, + }) + if err != nil { + t.Fatalf("CreateSession failed: %v", err) + } + return client, server, provider, session +} + +func skillProviderErrorHarness(t *testing.T, provider SkillProvider) (*Client, *jsonrpc2.Client, string) { + t.Helper() + client, server := newSkillProviderClient(t) + session := newSession("error-session", client.client, "", false) + session.registerSkillProvider(provider) + client.sessions[session.SessionID] = session + return client, server, session.SessionID +} + +func requestSkillProviderError(t *testing.T, server *jsonrpc2.Client, method string, params map[string]any) *jsonrpc2.Error { + t.Helper() + _, err := server.Request(t.Context(), method, params) + if err == nil { + t.Fatalf("%s succeeded unexpectedly", method) + } + rpcErr, ok := err.(*jsonrpc2.Error) + if !ok { + t.Fatalf("%s error = %T %v, want *jsonrpc2.Error", method, err, err) + } + return rpcErr +} + +func assertSkillProviderError(t *testing.T, rpcErr *jsonrpc2.Error, wantMessage string) { + t.Helper() + if rpcErr.Code != -32603 || rpcErr.Message != wantMessage { + t.Fatalf("error = %+v, want code -32603 message %q", rpcErr, wantMessage) + } + if rpcErr.Data != nil { + t.Fatalf("error data = %s, want omitted", rpcErr.Data) + } +} + +func assertSkillProviderFlag(t *testing.T, params json.RawMessage, wantPresent bool) { + t.Helper() + var payload map[string]any + if err := json.Unmarshal(params, &payload); err != nil { + t.Fatalf("failed to decode request params: %v", err) + } + got, present := payload["hasSkillProvider"] + if !wantPresent { + if present { + t.Fatalf("hasSkillProvider = %v, want omitted", got) + } + return + } + if got != true { + t.Fatalf("hasSkillProvider = %v, want true", got) + } + if _, present := payload["skillProvider"]; present { + t.Fatalf("skillProvider callback was serialized: %v", payload["skillProvider"]) + } +} diff --git a/go/types.go b/go/types.go index af4fd783fb..6bf2eb3b5b 100644 --- a/go/types.go +++ b/go/types.go @@ -3,6 +3,7 @@ package copilot import ( "context" "encoding/json" + "errors" "time" "github.com/github/copilot-sdk/go/rpc" @@ -1251,6 +1252,8 @@ func (c MCPHTTPServerConfig) MarshalJSON() ([]byte, error) { // CustomAgentConfig configures a custom agent. type CustomAgentConfig struct { + // Hooks contains declarative actions keyed by event name, active only for this agent. + Hooks map[string][]map[string]any `json:"hooks,omitempty"` // Name is the unique name of the custom agent Name string `json:"name"` // DisplayName is the display name for UI purposes @@ -1322,6 +1325,16 @@ type LargeToolOutputConfig struct { OutputDirectory string `json:"outputDir,omitempty"` } +// ImageGenerationConfig opts in to an authorized Copilot image model. +// Experimental: this API may change or be removed in a future release. +// Omission disables on create/cold resume and preserves resident resume state. +// Not persisted: re-supply after runtime restart. Policy, permissions, offline +// mode, and tool filters still apply. BYOK image generation is not supported. +type ImageGenerationConfig struct { + // Enabled opts in when true and disables image generation when false. + Enabled *bool `json:"enabled,omitempty"` +} + // ToolSearchConfig allows to configure tool search behavior. // Tool search defers tools to keep the model's active tool set small. // To override the tool-search tool's implementation, register a @@ -1444,10 +1457,35 @@ const ( AskUserVariantElicitation AskUserVariant = "elicitation" ) +// ErrSkillNotFound is returned by [SkillProvider.ReadSkill] when a listed skill +// is no longer available. It can be wrapped; the SDK checks it with [errors.Is]. +var ErrSkillNotFound = errors.New("skill not found") + +// SkillProvider supplies session-scoped skills from the SDK host. +// +// Experimental: this API may change or be removed in future SDK or CLI +// releases. Implementations must be safe for concurrent calls. +type SkillProvider interface { + // ListSkills returns catalog metadata for skills provided by this session. + // Return nil, nil to publish an empty catalog. + ListSkills(ctx context.Context) ([]rpc.SkillProviderDescriptor, error) + // ReadSkill returns the SKILL.md markdown for name. Return an error wrapping + // [ErrSkillNotFound] when the skill no longer exists. The markdown is + // ignored whenever a non-nil error is returned. + ReadSkill(ctx context.Context, name string) (string, error) +} + // SessionConfig configures a new session type SessionConfig struct { // SessionID is an optional custom session ID SessionID string + // Name names the session at creation, as session.name.set would, and is + // validated the same way: non-empty, no leading or trailing whitespace, at + // most 100 UTF-16 units, no control characters, and no double quotes. A name + // also makes the session persist from the start, so it can be listed and + // resumed without ever running a turn. Local sessions only: cloud creation + // rejects it. + Name string // ClientName identifies the application using the SDK. // Included in the User-Agent header for API requests. ClientName string @@ -1486,9 +1524,9 @@ type SessionConfig struct { // of instruction files (AGENTS.md, .github/copilot-instructions.md, etc.) after // successful file views. EnableOnDemandInstructionDiscovery *bool - // EnableFileHooks, when non-nil, controls loading of file-based hooks from - // .github/hooks/. This is separate from the Hooks callback parameter which - // gates SDK hook event registration. + // EnableFileHooks, when non-nil, controls repository-origin file hooks from + // .github/hooks/ and trusted repository-configured roots. It does not control + // explicit HookDirectories or Hooks callbacks. EnableFileHooks *bool // EnableHostGitOperations, when non-nil, controls git operations on the host // filesystem (branch detection, file status, commit history). When false, no @@ -1641,15 +1679,41 @@ type SessionConfig struct { // Agent is the name of the custom agent to activate when the session starts. // Must match the Name of one of the agents in CustomAgents. Agent string - // SkillDirectories is a list of directories to load skills from + // SkillDirectories contains explicit discovery-only skill roots, not filesystem grants. + // Available without EnableConfigDiscovery, subject to skill/managed disables. + // Relative paths resolve once when supplied against the request's effective WorkingDirectory; + // retained roots do not move on cwd changes. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. SkillDirectories []string + // SkillProvider supplies ephemeral SDK-hosted skills for this session. The + // provider is never serialized or persisted; re-supply it when resuming. + // + // Experimental: this API may change or be removed in future SDK or CLI + // releases. Implementations must be safe for concurrent calls. + SkillProvider SkillProvider `json:"-"` + // AgentDirectories contains explicit discovery-only agent roots, separate from CustomAgents. + // No filesystem grant. Available without EnableConfigDiscovery, subject to source/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. + AgentDirectories []string + // HookDirectories contains explicit discovery-only file-hook roots, separate from Hooks callbacks. + // No filesystem grant. Available without EnableConfigDiscovery or EnableFileHooks + // (repository-origin hooks only), subject to hook/managed disables. Relative paths resolve + // once when supplied against the request's effective WorkingDirectory; retained roots do not + // move. Nil and omission are equivalent; an empty non-nil list clears only the explicit SDK contribution. + HookDirectories []string // PluginDirectories is a list of local filesystem paths to Open Plugins-format // directories (https://open-plugins.com/) to load for this session. // Relative paths resolve against WorkingDirectory (or the runtime cwd if unset). // Treated as an explicit opt-in: plugin agents and rules load even when // EnableConfigDiscovery is false. PluginDirectories []string - // InstructionDirectories is a list of additional directories to search for custom instruction files + // InstructionDirectories contains explicit discovery-only instruction roots using existing SDK formats. + // No filesystem grant. Available without EnableConfigDiscovery, subject to instruction/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. InstructionDirectories []string // DisabledSkills is a list of skill names to disable DisabledSkills []string @@ -1668,6 +1732,9 @@ type SessionConfig struct { // defers rarely used tools behind a searchable index. When nil, the runtime // default applies. ToolSearch *ToolSearchConfig + // ImageGeneration is the non-persisted image generation opt-in. + // Experimental: this API may change or be removed in a future release. + ImageGeneration *ImageGenerationConfig // Memory configures the memory feature for the session. When omitted, the // runtime default applies. Memory *MemoryConfiguration @@ -1778,6 +1845,10 @@ type SessionConfig struct { // be set; if omitted, the runtime is expected to reject session creation // (fail-closed). Unset behaves exactly as before. EnableManagedSettings *bool + // EnforceManagedModelDefaults, when true, enforces locked managed model + // controls for this session. Conflicting changes are rejected; overridable + // managed defaults remain mutable. + EnforceManagedModelDefaults *bool // ManagedSettings supplies host-injected enterprise managed settings for // the session. Unlike EnableManagedSettings (which asks the runtime to // self-fetch account/org and device policy), this provides the managed @@ -1821,6 +1892,9 @@ type ManagedSettingsPermissions struct { // session. See the DisableBypassPermissionsMode constants for known values. // Newer values are forwarded unchanged so runtime policies remain fail-closed. DisableBypassPermissionsMode DisableBypassPermissionsMode `json:"disableBypassPermissionsMode,omitempty"` + // DisableAssistedPermissionsMode prevents Assisted Permissions from being + // activated when true. Nil or false imposes no restriction. + DisableAssistedPermissionsMode *bool `json:"disableAssistedPermissionsMode,omitempty"` // Deny lists operations that must always be denied. Unioned across layers. Deny []string `json:"deny,omitzero"` // Ask lists operations that must prompt for approval. Unioned across layers. @@ -1828,6 +1902,11 @@ type ManagedSettingsPermissions struct { // Allow lists operations permitted without prompting. Every declared allow // list across managed layers must admit an operation for it to be allowed. Allow []string `json:"allow,omitzero"` + // LimitTo is a closed-world host boundary expressed as Domain(hostname), + // Domain(IP), or Domain(*.example.com) rules. Schemes, ports, paths, + // queries, and fragments are rejected. Multiple managed layers intersect + // their lists. A present empty list denies all hosts. + LimitTo []string `json:"limitTo,omitzero"` } // ToolDefer controls whether a tool may be deferred (loaded lazily via tool @@ -1887,6 +1966,22 @@ type ToolInvocation struct { // disconnects, so background work must derive its own lifetime if it should // outlive the invocation. TraceContext context.Context + + // AgentID is the sub-agent instance that issued this call (the AgentID of + // its session events). It is empty for a root-agent call, and for every + // call when the runtime does not attribute sub-agent tool calls. + // + // Experimental: this field may change or be removed. + AgentID string + + // RequestID is the runtime request id of this call: the key + // session.tools.handlePendingToolCall and session.tools.listPendingRequests use. + // A root-agent call stays answerable after the session is resumed with + // pending work continued; a sub-agent's call can be answered only while that + // sub-agent is still running. + // + // Experimental: this field may change or be removed. + RequestID string } // ToolHandler executes a tool invocation. @@ -2164,9 +2259,9 @@ type ResumeSessionConfig struct { // EnableOnDemandInstructionDiscovery, when non-nil, controls on-demand discovery // of instruction files after successful file views. EnableOnDemandInstructionDiscovery *bool - // EnableFileHooks, when non-nil, controls loading of file-based hooks from - // .github/hooks/. This is separate from the Hooks callback parameter which - // gates SDK hook event registration. + // EnableFileHooks, when non-nil, controls repository-origin file hooks from + // .github/hooks/ and trusted repository-configured roots. It does not control + // explicit HookDirectories or Hooks callbacks. EnableFileHooks *bool // EnableHostGitOperations, when non-nil, controls git operations on the host // filesystem. @@ -2206,15 +2301,42 @@ type ResumeSessionConfig struct { // Agent is the name of the custom agent to activate when the session starts. // Must match the Name of one of the agents in CustomAgents. Agent string - // SkillDirectories is a list of directories to load skills from + // SkillDirectories contains explicit discovery-only skill roots, not filesystem grants. + // Available without EnableConfigDiscovery, subject to skill/managed disables. + // Relative paths resolve once when supplied against the request's effective WorkingDirectory; + // retained roots do not move on cwd changes. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. SkillDirectories []string + // SkillProvider supplies ephemeral SDK-hosted skills for this resumed + // session. Re-supply it on every resume; omitting it unbinds any previous + // provider. + // + // Experimental: this API may change or be removed in future SDK or CLI + // releases. Implementations must be safe for concurrent calls. + SkillProvider SkillProvider `json:"-"` + // AgentDirectories contains explicit discovery-only agent roots, separate from CustomAgents. + // No filesystem grant. Available without EnableConfigDiscovery, subject to source/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. + AgentDirectories []string + // HookDirectories contains explicit discovery-only file-hook roots, separate from Hooks callbacks. + // No filesystem grant. Available without EnableConfigDiscovery or EnableFileHooks + // (repository-origin hooks only), subject to hook/managed disables. Relative paths resolve + // once when supplied against the request's effective WorkingDirectory; retained roots do not + // move. Nil and omission are equivalent; an empty non-nil list clears only the explicit SDK contribution. + HookDirectories []string // PluginDirectories is a list of local filesystem paths to Open Plugins-format // directories (https://open-plugins.com/) to load for this session. // Relative paths resolve against WorkingDirectory (or the runtime cwd if unset). // Treated as an explicit opt-in: plugin agents and rules load even when // EnableConfigDiscovery is false. PluginDirectories []string - // InstructionDirectories is a list of additional directories to search for custom instruction files + // InstructionDirectories contains explicit discovery-only instruction roots using existing SDK formats. + // No filesystem grant. Available without EnableConfigDiscovery, subject to instruction/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. InstructionDirectories []string // DisabledSkills is a list of skill names to disable DisabledSkills []string @@ -2232,6 +2354,9 @@ type ResumeSessionConfig struct { // defers rarely used tools behind a searchable index. When nil, the runtime // default applies. ToolSearch *ToolSearchConfig + // ImageGeneration is the non-persisted image generation opt-in. + // Experimental: this API may change or be removed in a future release. + ImageGeneration *ImageGenerationConfig // Memory configures the memory feature for the session. When omitted, the // runtime default applies. Memory *MemoryConfiguration @@ -2323,6 +2448,9 @@ type ResumeSessionConfig struct { // SessionConfig.EnableManagedSettings. Re-supply on resume so the runtime // re-applies the managed-settings self-fetch after a CLI process restart. EnableManagedSettings *bool + // EnforceManagedModelDefaults re-applies managed model lock enforcement on + // resume. See SessionConfig.EnforceManagedModelDefaults. + EnforceManagedModelDefaults *bool // ManagedSettings re-injects host-provided managed settings on resume. See // SessionConfig.ManagedSettings. It must be re-supplied on resume: it // replaces the prior injected layer, and omitting it clears that layer so @@ -2453,6 +2581,8 @@ const ( AutoTierBalance = rpc.AutoTierBalance // AutoTierIntelligence selects the intelligence routing tier. AutoTierIntelligence = rpc.AutoTierIntelligence + // AutoTierFast selects the integrator-only latency preset. + AutoTierFast = rpc.AutoTierFast ) // CapiSessionOptions configures provider-scoped Copilot API (CAPI) session behavior. @@ -2772,6 +2902,7 @@ type SessionLifecycleHandler func(event SessionLifecycleEvent) type createSessionRequest struct { Model string `json:"model,omitempty"` SessionID string `json:"sessionId,omitempty"` + Name string `json:"name,omitempty"` ClientName string `json:"clientName,omitempty"` ReasoningEffort string `json:"reasoningEffort,omitempty"` ReasoningSummary ReasoningSummary `json:"reasoningSummary,omitempty"` @@ -2826,14 +2957,18 @@ type createSessionRequest struct { EnableHostGitOperations *bool `json:"enableHostGitOperations,omitempty"` EnableSessionStore *bool `json:"enableSessionStore,omitempty"` EnableSkills *bool `json:"enableSkills,omitempty"` - SkillDirectories []string `json:"skillDirectories,omitempty"` + HasSkillProvider *bool `json:"hasSkillProvider,omitempty"` + SkillDirectories []string `json:"skillDirectories,omitzero"` + AgentDirectories []string `json:"agentDirectories,omitzero"` + HookDirectories []string `json:"hookDirectories,omitzero"` PluginDirectories []string `json:"pluginDirectories,omitempty"` - InstructionDirectories []string `json:"instructionDirectories,omitempty"` + InstructionDirectories []string `json:"instructionDirectories,omitzero"` DisabledSkills []string `json:"disabledSkills,omitempty"` DisabledMCPServers *[]string `json:"disabledMcpServers,omitempty"` InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` LargeOutput *LargeToolOutputConfig `json:"largeOutput,omitempty"` ToolSearch *ToolSearchConfig `json:"toolSearch,omitempty"` + ImageGeneration *ImageGenerationConfig `json:"imageGeneration,omitempty"` Memory *MemoryConfiguration `json:"memory,omitempty"` Commands []wireCommand `json:"commands,omitempty"` RequestElicitation *bool `json:"requestElicitation,omitempty"` @@ -2852,6 +2987,7 @@ type createSessionRequest struct { ExpAssignments *CopilotExpAssignmentResponse `json:"expAssignments,omitempty"` FeatureFlags *map[string]bool `json:"featureFlags,omitempty"` EnableManagedSettings *bool `json:"enableManagedSettings,omitempty"` + EnforceManagedModelDefaults *bool `json:"enforceManagedModelDefaults,omitempty"` ManagedSettings *ManagedSettings `json:"managedSettings,omitempty"` Traceparent string `json:"traceparent,omitempty"` Tracestate string `json:"tracestate,omitempty"` @@ -2916,6 +3052,7 @@ type resumeSessionRequest struct { EnableHostGitOperations *bool `json:"enableHostGitOperations,omitempty"` EnableSessionStore *bool `json:"enableSessionStore,omitempty"` EnableSkills *bool `json:"enableSkills,omitempty"` + HasSkillProvider *bool `json:"hasSkillProvider,omitempty"` DisableResume *bool `json:"disableResume,omitempty"` ContinuePendingWork *bool `json:"continuePendingWork,omitempty"` AllowTranscriptRecovery *bool `json:"allowTranscriptRecovery,omitempty"` @@ -2930,14 +3067,17 @@ type resumeSessionRequest struct { CustomAgents []CustomAgentConfig `json:"customAgents,omitempty"` DefaultAgent *DefaultAgentConfig `json:"defaultAgent,omitempty"` Agent string `json:"agent,omitempty"` - SkillDirectories []string `json:"skillDirectories,omitempty"` + SkillDirectories []string `json:"skillDirectories,omitzero"` + AgentDirectories []string `json:"agentDirectories,omitzero"` + HookDirectories []string `json:"hookDirectories,omitzero"` PluginDirectories []string `json:"pluginDirectories,omitempty"` - InstructionDirectories []string `json:"instructionDirectories,omitempty"` + InstructionDirectories []string `json:"instructionDirectories,omitzero"` DisabledSkills []string `json:"disabledSkills,omitempty"` DisabledMCPServers *[]string `json:"disabledMcpServers,omitempty"` InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` LargeOutput *LargeToolOutputConfig `json:"largeOutput,omitempty"` ToolSearch *ToolSearchConfig `json:"toolSearch,omitempty"` + ImageGeneration *ImageGenerationConfig `json:"imageGeneration,omitempty"` Memory *MemoryConfiguration `json:"memory,omitempty"` Commands []wireCommand `json:"commands,omitempty"` RequestElicitation *bool `json:"requestElicitation,omitempty"` @@ -2956,6 +3096,7 @@ type resumeSessionRequest struct { ExpAssignments *CopilotExpAssignmentResponse `json:"expAssignments,omitempty"` FeatureFlags *map[string]bool `json:"featureFlags,omitempty"` EnableManagedSettings *bool `json:"enableManagedSettings,omitempty"` + EnforceManagedModelDefaults *bool `json:"enforceManagedModelDefaults,omitempty"` ManagedSettings *ManagedSettings `json:"managedSettings,omitempty"` Traceparent string `json:"traceparent,omitempty"` Tracestate string `json:"tracestate,omitempty"` diff --git a/go/zsession_events.go b/go/zsession_events.go index 794a765fa8..81bb0f2c25 100644 --- a/go/zsession_events.go +++ b/go/zsession_events.go @@ -13,6 +13,7 @@ type ( AgentInterruptedCancelPhase = rpc.AgentInterruptedCancelPhase AgentInterruptedData = rpc.AgentInterruptedData AgentModelPolicy = rpc.AgentModelPolicy + AiCreditsStatus = rpc.AiCreditsStatus AssistantFusionPhaseActivityData = rpc.AssistantFusionPhaseActivityData AssistantFusionPhaseCompletedData = rpc.AssistantFusionPhaseCompletedData AssistantFusionPhaseFailedData = rpc.AssistantFusionPhaseFailedData @@ -151,6 +152,8 @@ type ( HumanResponseRecordedResponseResponseKind = rpc.HumanResponseRecordedResponseResponseKind HumanResponseRecordedResponseUserInput = rpc.HumanResponseRecordedResponseUserInput IndexedSearchState = rpc.IndexedSearchState + ManagedPermissionsContext = rpc.ManagedPermissionsContext + ManagedPluginProgressPhase = rpc.ManagedPluginProgressPhase ManagedSettingsEnforcedAction = rpc.ManagedSettingsEnforcedAction ManagedSettingsEnforcedEscalation = rpc.ManagedSettingsEnforcedEscalation ManagedSettingsResolvedData = rpc.ManagedSettingsResolvedData @@ -189,9 +192,14 @@ type ( ModelCallFinalResultData = rpc.ModelCallFinalResultData ModelCallFinishedData = rpc.ModelCallFinishedData ModelCallFinishedOutcome = rpc.ModelCallFinishedOutcome + ModelCallRequestBodyEncoding = rpc.ModelCallRequestBodyEncoding ModelCallStartData = rpc.ModelCallStartData + ModelCallWebSocketFallbackErrorKind = rpc.ModelCallWebSocketFallbackErrorKind + ModelCallWebSocketFallbackReason = rpc.ModelCallWebSocketFallbackReason ModelChangeSource = rpc.ModelChangeSource ModelDeselectedReason = rpc.ModelDeselectedReason + ModelProviderKind = rpc.ModelProviderKind + ModelProviderRef = rpc.ModelProviderRef OmittedBinaryOmittedReason = rpc.OmittedBinaryOmittedReason OmittedBinaryResult = rpc.OmittedBinaryResult OmittedBinaryType = rpc.OmittedBinaryType @@ -272,6 +280,8 @@ type ( PermissionRule = rpc.PermissionRule PermissionSandboxPathGrant = rpc.PermissionSandboxPathGrant PermissionSandboxPathGrantAccess = rpc.PermissionSandboxPathGrantAccess + PermissionWriteFileContent = rpc.PermissionWriteFileContent + PermissionWriteFileEdit = rpc.PermissionWriteFileEdit PersistedBinaryImage = rpc.PersistedBinaryImage PersistedBinaryImageType = rpc.PersistedBinaryImageType PersistedBinaryResult = rpc.PersistedBinaryResult @@ -279,6 +289,17 @@ type ( PlanChangedOperation = rpc.PlanChangedOperation PossibleURL = rpc.PossibleURL PromptCacheBreakData = rpc.PromptCacheBreakData + ProviderMonthlyUsage = rpc.ProviderMonthlyUsage + ProviderMonthlyUsageScope = rpc.ProviderMonthlyUsageScope + ProviderMonthlyUsageState = rpc.ProviderMonthlyUsageState + ProviderQuotaAccessState = rpc.ProviderQuotaAccessState + ProviderQuotaAcquisitionStatus = rpc.ProviderQuotaAcquisitionStatus + ProviderQuotaBudgetMetadata = rpc.ProviderQuotaBudgetMetadata + ProviderQuotaCapacityState = rpc.ProviderQuotaCapacityState + ProviderQuotaObservationKind = rpc.ProviderQuotaObservationKind + ProviderQuotaQuantityKind = rpc.ProviderQuotaQuantityKind + ProviderQuotaState = rpc.ProviderQuotaState + ProviderQuotaUnit = rpc.ProviderQuotaUnit RawCitationLocation = rpc.RawCitationLocation RawHumanResponseRecordedResponse = rpc.RawHumanResponseRecordedResponse RawPermissionPromptRequest = rpc.RawPermissionPromptRequest @@ -335,6 +356,7 @@ type ( SessionLimitsExhaustedRequestedData = rpc.SessionLimitsExhaustedRequestedData SessionLimitsExhaustedResponse = rpc.SessionLimitsExhaustedResponse SessionLimitsExhaustedResponseAction = rpc.SessionLimitsExhaustedResponseAction + SessionManagedPluginProgressData = rpc.SessionManagedPluginProgressData SessionManagedSettingsEnforcedData = rpc.SessionManagedSettingsEnforcedData SessionManagedSettingsResolvedData = rpc.SessionManagedSettingsResolvedData SessionMCPServerNeedsReconnectData = rpc.SessionMCPServerNeedsReconnectData @@ -349,6 +371,7 @@ type ( SessionPermissionRecoveryData = rpc.SessionPermissionRecoveryData SessionPermissionsChangedData = rpc.SessionPermissionsChangedData SessionPlanChangedData = rpc.SessionPlanChangedData + SessionQuotaObservationData = rpc.SessionQuotaObservationData SessionRemoteSteerableChangedData = rpc.SessionRemoteSteerableChangedData SessionResumeData = rpc.SessionResumeData SessionScheduleCancelledData = rpc.SessionScheduleCancelledData @@ -462,6 +485,16 @@ type ( ToolUserRequestedData = rpc.ToolUserRequestedData UIEphemeralQueryData = rpc.UIEphemeralQueryData UIEphemeralQueryPhase = rpc.UIEphemeralQueryPhase + UsageAccountingIdentity = rpc.UsageAccountingIdentity + UsageGetMetricsResult = rpc.UsageGetMetricsResult + UsageMetricsAgentMetric = rpc.UsageMetricsAgentMetric + UsageMetricsCodeChanges = rpc.UsageMetricsCodeChanges + UsageMetricsModelMetric = rpc.UsageMetricsModelMetric + UsageMetricsModelMetricRequests = rpc.UsageMetricsModelMetricRequests + UsageMetricsModelMetricTokenDetail = rpc.UsageMetricsModelMetricTokenDetail + UsageMetricsModelMetricUsage = rpc.UsageMetricsModelMetricUsage + UsageMetricsProviderModelMetric = rpc.UsageMetricsProviderModelMetric + UsageMetricsTokenDetail = rpc.UsageMetricsTokenDetail UserInputCompletedData = rpc.UserInputCompletedData UserInputRequestedData = rpc.UserInputRequestedData UserMessageAgentMode = rpc.UserMessageAgentMode @@ -505,6 +538,9 @@ const ( AgentInterruptedCancelPhasePreFirstToken = rpc.AgentInterruptedCancelPhasePreFirstToken AgentModelPolicyPreferred = rpc.AgentModelPolicyPreferred AgentModelPolicyRequired = rpc.AgentModelPolicyRequired + AiCreditsStatusComplete = rpc.AiCreditsStatusComplete + AiCreditsStatusPartial = rpc.AiCreditsStatusPartial + AiCreditsStatusUnavailable = rpc.AiCreditsStatusUnavailable AssistantMessageToolRequestCallerTypeProgram = rpc.AssistantMessageToolRequestCallerTypeProgram AssistantMessageToolRequestTypeCustom = rpc.AssistantMessageToolRequestTypeCustom AssistantMessageToolRequestTypeFunction = rpc.AssistantMessageToolRequestTypeFunction @@ -554,7 +590,6 @@ const ( AutopilotObjectiveChangedStatusCapReached = rpc.AutopilotObjectiveChangedStatusCapReached AutopilotObjectiveChangedStatusCompleted = rpc.AutopilotObjectiveChangedStatusCompleted AutopilotObjectiveChangedStatusPaused = rpc.AutopilotObjectiveChangedStatusPaused - AutoTierFast = rpc.AutoTierFast AutoTierSwitchFailureReasonPolicyRejected = rpc.AutoTierSwitchFailureReasonPolicyRejected AutoTierSwitchFailureReasonRequestFailed = rpc.AutoTierSwitchFailureReasonRequestFailed AutoTierSwitchFailureReasonSetupFailed = rpc.AutoTierSwitchFailureReasonSetupFailed @@ -640,6 +675,10 @@ const ( IndexedSearchStateFailed = rpc.IndexedSearchStateFailed IndexedSearchStateReady = rpc.IndexedSearchStateReady IndexedSearchStateStarting = rpc.IndexedSearchStateStarting + ManagedPluginProgressPhaseComplete = rpc.ManagedPluginProgressPhaseComplete + ManagedPluginProgressPhaseInitializing = rpc.ManagedPluginProgressPhaseInitializing + ManagedPluginProgressPhaseInstalling = rpc.ManagedPluginProgressPhaseInstalling + ManagedPluginProgressPhaseUpdating = rpc.ManagedPluginProgressPhaseUpdating ManagedSettingsEnforcedActionBypassPermissionsBlocked = rpc.ManagedSettingsEnforcedActionBypassPermissionsBlocked ManagedSettingsEnforcedEscalationAllowAll = rpc.ManagedSettingsEnforcedEscalationAllowAll ManagedSettingsEnforcedEscalationApproveAll = rpc.ManagedSettingsEnforcedEscalationApproveAll @@ -667,6 +706,7 @@ const ( MCPOauthRequestReasonRefresh = rpc.MCPOauthRequestReasonRefresh MCPOauthRequestReasonUpscope = rpc.MCPOauthRequestReasonUpscope MCPOauthRequiredStaticClientConfigGrantTypeClientCredentials = rpc.MCPOauthRequiredStaticClientConfigGrantTypeClientCredentials + MCPServerSourceAccount = rpc.MCPServerSourceAccount MCPServerSourceBuiltin = rpc.MCPServerSourceBuiltin MCPServerSourceManaged = rpc.MCPServerSourceManaged MCPServerSourcePlugin = rpc.MCPServerSourcePlugin @@ -704,6 +744,26 @@ const ( ModelCallFinishedOutcomeError = rpc.ModelCallFinishedOutcomeError ModelCallFinishedOutcomeRejected = rpc.ModelCallFinishedOutcomeRejected ModelCallFinishedOutcomeSuccess = rpc.ModelCallFinishedOutcomeSuccess + ModelCallRequestBodyEncodingGzip = rpc.ModelCallRequestBodyEncodingGzip + ModelCallRequestBodyEncodingIdentity = rpc.ModelCallRequestBodyEncodingIdentity + ModelCallRequestBodyEncodingZstd = rpc.ModelCallRequestBodyEncodingZstd + ModelCallWebSocketFallbackErrorKindClosedByPeer = rpc.ModelCallWebSocketFallbackErrorKindClosedByPeer + ModelCallWebSocketFallbackErrorKindClosedLocally = rpc.ModelCallWebSocketFallbackErrorKindClosedLocally + ModelCallWebSocketFallbackErrorKindConfiguration = rpc.ModelCallWebSocketFallbackErrorKindConfiguration + ModelCallWebSocketFallbackErrorKindConnectionRefused = rpc.ModelCallWebSocketFallbackErrorKindConnectionRefused + ModelCallWebSocketFallbackErrorKindConnectionReset = rpc.ModelCallWebSocketFallbackErrorKindConnectionReset + ModelCallWebSocketFallbackErrorKindDns = rpc.ModelCallWebSocketFallbackErrorKindDns + ModelCallWebSocketFallbackErrorKindHTTPStatus = rpc.ModelCallWebSocketFallbackErrorKindHTTPStatus + ModelCallWebSocketFallbackErrorKindNotConnected = rpc.ModelCallWebSocketFallbackErrorKindNotConnected + ModelCallWebSocketFallbackErrorKindOther = rpc.ModelCallWebSocketFallbackErrorKindOther + ModelCallWebSocketFallbackErrorKindProtocol = rpc.ModelCallWebSocketFallbackErrorKindProtocol + ModelCallWebSocketFallbackErrorKindTimeout = rpc.ModelCallWebSocketFallbackErrorKindTimeout + ModelCallWebSocketFallbackErrorKindTls = rpc.ModelCallWebSocketFallbackErrorKindTls + ModelCallWebSocketFallbackReasonAPIError = rpc.ModelCallWebSocketFallbackReasonAPIError + ModelCallWebSocketFallbackReasonConnectFailed = rpc.ModelCallWebSocketFallbackReasonConnectFailed + ModelCallWebSocketFallbackReasonConnectionUnavailable = rpc.ModelCallWebSocketFallbackReasonConnectionUnavailable + ModelCallWebSocketFallbackReasonSendFailed = rpc.ModelCallWebSocketFallbackReasonSendFailed + ModelCallWebSocketFallbackReasonTransportFailed = rpc.ModelCallWebSocketFallbackReasonTransportFailed ModelChangeSourceAgent = rpc.ModelChangeSourceAgent ModelChangeSourceAutomatic = rpc.ModelChangeSourceAutomatic ModelChangeSourceAutoTierRecommendation = rpc.ModelChangeSourceAutoTierRecommendation @@ -718,6 +778,8 @@ const ( ModelChangeSourceSettingsCommand = rpc.ModelChangeSourceSettingsCommand ModelChangeSourceStartup = rpc.ModelChangeSourceStartup ModelDeselectedReasonProviderWithdrawn = rpc.ModelDeselectedReasonProviderWithdrawn + ModelProviderKindCopilot = rpc.ModelProviderKindCopilot + ModelProviderKindLoki = rpc.ModelProviderKindLoki OmittedBinaryOmittedReasonAssetUnavailable = rpc.OmittedBinaryOmittedReasonAssetUnavailable OmittedBinaryOmittedReasonTooLarge = rpc.OmittedBinaryOmittedReasonTooLarge OmittedBinaryTypeImage = rpc.OmittedBinaryTypeImage @@ -736,6 +798,10 @@ const ( PermissionApprovalEvaluationReasonCodeActionTooLong = rpc.PermissionApprovalEvaluationReasonCodeActionTooLong PermissionApprovalEvaluationReasonCodeArgumentBindingUnreviewable = rpc.PermissionApprovalEvaluationReasonCodeArgumentBindingUnreviewable PermissionApprovalEvaluationReasonCodeAuthorizationHistoryIncomplete = rpc.PermissionApprovalEvaluationReasonCodeAuthorizationHistoryIncomplete + PermissionApprovalEvaluationReasonCodeContentExcluded = rpc.PermissionApprovalEvaluationReasonCodeContentExcluded + PermissionApprovalEvaluationReasonCodeDynamicSource = rpc.PermissionApprovalEvaluationReasonCodeDynamicSource + PermissionApprovalEvaluationReasonCodeExecutableTooLarge = rpc.PermissionApprovalEvaluationReasonCodeExecutableTooLarge + PermissionApprovalEvaluationReasonCodeExecutableUnavailable = rpc.PermissionApprovalEvaluationReasonCodeExecutableUnavailable PermissionApprovalEvaluationReasonCodeInactive = rpc.PermissionApprovalEvaluationReasonCodeInactive PermissionApprovalEvaluationReasonCodeInherited = rpc.PermissionApprovalEvaluationReasonCodeInherited PermissionApprovalEvaluationReasonCodeInterpreterTooLarge = rpc.PermissionApprovalEvaluationReasonCodeInterpreterTooLarge @@ -754,11 +820,14 @@ const ( PermissionApprovalEvaluationReasonCodeSandboxBypass = rpc.PermissionApprovalEvaluationReasonCodeSandboxBypass PermissionApprovalEvaluationReasonCodeShellEnvironmentUnreviewable = rpc.PermissionApprovalEvaluationReasonCodeShellEnvironmentUnreviewable PermissionApprovalEvaluationReasonCodeTooLarge = rpc.PermissionApprovalEvaluationReasonCodeTooLarge + PermissionApprovalEvaluationReasonCodeTooManySources = rpc.PermissionApprovalEvaluationReasonCodeTooManySources PermissionApprovalEvaluationReasonCodeUnavailable = rpc.PermissionApprovalEvaluationReasonCodeUnavailable PermissionApprovalEvaluationReasonCodeUnknown = rpc.PermissionApprovalEvaluationReasonCodeUnknown PermissionApprovalEvaluationReasonCodeUnreadable = rpc.PermissionApprovalEvaluationReasonCodeUnreadable PermissionApprovalEvaluationReasonCodeUnrepresentablePath = rpc.PermissionApprovalEvaluationReasonCodeUnrepresentablePath PermissionApprovalEvaluationReasonCodeUnreviewableScriptInvocation = rpc.PermissionApprovalEvaluationReasonCodeUnreviewableScriptInvocation + PermissionApprovalEvaluationReasonCodeUnsupportedCommandShape = rpc.PermissionApprovalEvaluationReasonCodeUnsupportedCommandShape + PermissionApprovalEvaluationReasonCodeUnsupportedSource = rpc.PermissionApprovalEvaluationReasonCodeUnsupportedSource PermissionDecisionSourceAuthorizationCarryForward = rpc.PermissionDecisionSourceAuthorizationCarryForward PermissionMessageAuthorizationPolarityDenial = rpc.PermissionMessageAuthorizationPolarityDenial PermissionMessageAuthorizationPolarityGrant = rpc.PermissionMessageAuthorizationPolarityGrant @@ -848,6 +917,36 @@ const ( PlanChangedOperationCreate = rpc.PlanChangedOperationCreate PlanChangedOperationDelete = rpc.PlanChangedOperationDelete PlanChangedOperationUpdate = rpc.PlanChangedOperationUpdate + ProviderMonthlyUsageScopeUnknown = rpc.ProviderMonthlyUsageScopeUnknown + ProviderMonthlyUsageScopeUser = rpc.ProviderMonthlyUsageScopeUser + ProviderMonthlyUsageStateAvailable = rpc.ProviderMonthlyUsageStateAvailable + ProviderMonthlyUsageStateNoPolicy = rpc.ProviderMonthlyUsageStateNoPolicy + ProviderMonthlyUsageStateUnavailable = rpc.ProviderMonthlyUsageStateUnavailable + ProviderMonthlyUsageStateUnknown = rpc.ProviderMonthlyUsageStateUnknown + ProviderQuotaAccessStateAllowed = rpc.ProviderQuotaAccessStateAllowed + ProviderQuotaAccessStateDenied = rpc.ProviderQuotaAccessStateDenied + ProviderQuotaAccessStateNotRequired = rpc.ProviderQuotaAccessStateNotRequired + ProviderQuotaAccessStateUnavailable = rpc.ProviderQuotaAccessStateUnavailable + ProviderQuotaAccessStateUnknown = rpc.ProviderQuotaAccessStateUnknown + ProviderQuotaAcquisitionStatusFailed = rpc.ProviderQuotaAcquisitionStatusFailed + ProviderQuotaAcquisitionStatusSucceeded = rpc.ProviderQuotaAcquisitionStatusSucceeded + ProviderQuotaAcquisitionStatusUnavailable = rpc.ProviderQuotaAcquisitionStatusUnavailable + ProviderQuotaCapacityStateAvailable = rpc.ProviderQuotaCapacityStateAvailable + ProviderQuotaCapacityStateExhausted = rpc.ProviderQuotaCapacityStateExhausted + ProviderQuotaCapacityStateNotApplicable = rpc.ProviderQuotaCapacityStateNotApplicable + ProviderQuotaCapacityStateNotRequired = rpc.ProviderQuotaCapacityStateNotRequired + ProviderQuotaCapacityStateUnavailable = rpc.ProviderQuotaCapacityStateUnavailable + ProviderQuotaCapacityStateUnknown = rpc.ProviderQuotaCapacityStateUnknown + ProviderQuotaCapacityStateUnlimited = rpc.ProviderQuotaCapacityStateUnlimited + ProviderQuotaObservationKindAccountSnapshot = rpc.ProviderQuotaObservationKindAccountSnapshot + ProviderQuotaObservationKindAdmissionState = rpc.ProviderQuotaObservationKindAdmissionState + ProviderQuotaQuantityKindAdvisoryBalance = rpc.ProviderQuotaQuantityKindAdvisoryBalance + ProviderQuotaQuantityKindAuthoritativeBudget = rpc.ProviderQuotaQuantityKindAuthoritativeBudget + ProviderQuotaQuantityKindNone = rpc.ProviderQuotaQuantityKindNone + ProviderQuotaUnitAiCredits = rpc.ProviderQuotaUnitAiCredits + ProviderQuotaUnitRequests = rpc.ProviderQuotaUnitRequests + ProviderQuotaUnitTokens = rpc.ProviderQuotaUnitTokens + ProviderQuotaUnitUnknown = rpc.ProviderQuotaUnitUnknown ReasoningSummaryConcise = rpc.ReasoningSummaryConcise ReasoningSummaryDetailed = rpc.ReasoningSummaryDetailed ReasoningSummaryNone = rpc.ReasoningSummaryNone @@ -856,6 +955,7 @@ const ( RecommendedAutoTierIntelligence = rpc.RecommendedAutoTierIntelligence RemediationActionAllowSandboxOutbound = rpc.RemediationActionAllowSandboxOutbound RemediationActionReviewSandboxPolicy = rpc.RemediationActionReviewSandboxPolicy + RemediationActionRewindConversation = rpc.RemediationActionRewindConversation RemediationActionShowAccount = rpc.RemediationActionShowAccount RemediationActionSignIn = rpc.RemediationActionSignIn RemediationActionSwitchAccount = rpc.RemediationActionSwitchAccount @@ -955,6 +1055,7 @@ const ( SessionEventTypeSessionInfo = rpc.SessionEventTypeSessionInfo SessionEventTypeSessionLimitsExhaustedCompleted = rpc.SessionEventTypeSessionLimitsExhaustedCompleted SessionEventTypeSessionLimitsExhaustedRequested = rpc.SessionEventTypeSessionLimitsExhaustedRequested + SessionEventTypeSessionManagedPluginProgress = rpc.SessionEventTypeSessionManagedPluginProgress SessionEventTypeSessionManagedSettingsEnforced = rpc.SessionEventTypeSessionManagedSettingsEnforced SessionEventTypeSessionManagedSettingsResolved = rpc.SessionEventTypeSessionManagedSettingsResolved SessionEventTypeSessionMCPServerNeedsReconnect = rpc.SessionEventTypeSessionMCPServerNeedsReconnect @@ -968,6 +1069,7 @@ const ( SessionEventTypeSessionPermissionRecovery = rpc.SessionEventTypeSessionPermissionRecovery SessionEventTypeSessionPermissionsChanged = rpc.SessionEventTypeSessionPermissionsChanged SessionEventTypeSessionPlanChanged = rpc.SessionEventTypeSessionPlanChanged + SessionEventTypeSessionQuotaObservation = rpc.SessionEventTypeSessionQuotaObservation SessionEventTypeSessionRemoteSteerableChanged = rpc.SessionEventTypeSessionRemoteSteerableChanged SessionEventTypeSessionResume = rpc.SessionEventTypeSessionResume SessionEventTypeSessionScheduleCancelled = rpc.SessionEventTypeSessionScheduleCancelled diff --git a/java/README.md b/java/README.md index cc2c5cf3a4..cb4b2d9c12 100644 --- a/java/README.md +++ b/java/README.md @@ -76,7 +76,7 @@ implementation 'com.github:copilot-sdk-java:1.0.15-preview.1-SNAPSHOT' ## In-process mode (experimental) -The SDK supports running the Copilot runtime **in-process** as a native library instead of spawning a separate CLI process. This eliminates process management overhead and simplifies deployment. In-process mode is currently experimental and supported on **linux-x64** (glibc), **linux-arm64** (glibc), **linuxmusl-x64**, **win32-x64**, **win32-arm64**, **darwin-x64**, and **darwin-arm64**. +The SDK supports running the Copilot runtime **in-process** as a native library instead of spawning a separate CLI process. This eliminates process management overhead and simplifies deployment. In-process mode is currently experimental and supported on **linux-x64** (glibc), **linux-arm64** (glibc), **linuxmusl-x64**, **linuxmusl-arm64**, **win32-x64**, **win32-arm64**, **darwin-x64**, and **darwin-arm64**. Because in-process mode is experimental, see the [Using experimental APIs](#using-experimental-apis) section for how to opt in. @@ -99,7 +99,7 @@ Add both the SDK and the platform-specific native runtime to your project: ${copilot.version} linux-x64 - + net.java.dev.jna @@ -131,7 +131,12 @@ instead, or configure both transports. GitHub environment name and compute ID ar required; there is no implicit local listener. The host's `getUrl()`, `getToken()`, and `getPid()` may return `null`; `getEnvironmentId()` returns the GitHub environment ID when configured. Environment list/get/delete operations are available only -through the generated RPC API. +through the generated RPC API. Call `host.listSessions()` to read the complete +advertised catalog of live and dormant sessions. +Use `AhpHostOptions.setComputeId(...)` to reuse the durable catalog across local +and Mission Control hosting; it must agree with the GitHub environment's compute +ID when both are supplied. The runtime persists an omitted local-only identity. +Publication survives host shutdown; dormant application sessions require your resume callback. See [runtime-supervised AHP hosting](../docs/runtime-supervised-host.md) for creation and resume callbacks, resident-session publication, ownership, and shared-snapshot E2Es. @@ -183,6 +188,24 @@ public class CopilotSDK { } ``` +`client.forceStop()` retires tracked sessions locally without `session.detach` +RPCs. Retained session objects reject new work and subscriptions, unused handler +captures are released, and pending plain and structured response waits fail. +Already-admitted event handlers and response continuations are not joined. +Forced retirement also drops callbacks when a graceful `session.close()` is +already awaiting detach. Graceful close fails pending response waits without +joining their continuations; ordinary callbacks remain active until detach completes. +Plain response waits preserve terminal results and errors already received before +retirement, even when a blocked continuation delays forwarding them to the caller. +Graceful owned-process shutdown over stdio waits for the runtime transport and +launcher to exit. Over TCP, it closes the connection and terminates the owned +process after the shutdown acknowledgment, without waiting for peer EOF. +Both preserve intentionally detached services; failed or forced shutdown retains +process-tree cleanup. +For a custom TCP launcher that spawns the runtime as a child, graceful cleanup +terminates only the launcher. The launcher must supervise and reap its runtime +child; a shutdown acknowledgment alone does not prove that child exited. + When targeting MCP tools configured through `setMcpServers(...)`, remember the runtime tool name is `-`. For `setAvailableTools(...)` and `setExcludedTools(...)`, prefer the source-qualified filter form @@ -198,6 +221,7 @@ Register `setOnSubagentStart` and `setOnSubagentStop` on `SessionHooks` to inspe the parent session and subagent metadata around each child run: ```java +import com.github.copilot.rpc.PermissionHandler; import com.github.copilot.rpc.SessionConfig; import com.github.copilot.rpc.SessionHooks; import com.github.copilot.rpc.SubagentStartHookOutput; @@ -211,7 +235,7 @@ var hooks = new SessionHooks() .setOnSubagentStop((input, invocation) -> CompletableFuture.completedFuture( new SubagentStopHookOutput(null, null, input.response()))); -var config = new SessionConfig().setHooks(hooks); +var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setHooks(hooks); ``` `SubagentStartHookInput` includes the parent `sessionId`, `timestamp`, `cwd`, @@ -286,6 +310,51 @@ provider errors, and invalid token responses reject that operation instead of falling back to ambient authentication. Idle sessions refresh only before their next credential-consuming operation; there is no background refresh timer. +### Skill providers (experimental) + +`SessionConfig.setSkillProvider(...)` registers session-scoped skills that the +runtime can list and read on demand. The API is experimental; see +[Using experimental APIs](#using-experimental-apis) before compiling code that +references it. + +```java +import com.github.copilot.SkillProvider; +import com.github.copilot.SkillProviderDescriptor; + +SkillProvider provider = new SkillProvider() { + @Override + public CompletableFuture> listSkills() { + return CompletableFuture.completedFuture(List.of( + new SkillProviderDescriptor("team-plan", "Team planning guidance", true, false, null))); + } + + @Override + public CompletableFuture readSkill(String name) { + if (!name.equals("team-plan")) { + return CompletableFuture.completedFuture(null); // not found + } + return CompletableFuture.completedFuture("# Team plan\nWrite a concise monthly team plan."); + } +}; + +var config = new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setEnableSkills(true) + .setSkillProvider(provider); +``` + +Provider callbacks may be invoked concurrently, so implementations should be +thread-safe. When the runtime cancels a call, for example after its 30-second +limit or when the session disconnects, the SDK calls `cancel(true)` on the +returned future; check `isCancelled()` or attach a completion callback to stop +early. The provider is not persisted with the session; pass it again via +`ResumeSessionConfig.setSkillProvider(...)` on every resume. Resuming without a +provider unbinds any provider the session had. In +`CopilotClientMode.EMPTY`, explicitly set `setEnableSkills(true)` if the +assistant should use skills, because empty mode disables skill loading by +default. Skill providers are local-session only and are rejected for cloud +sessions. + ### Typed MCP installation and removal payloads (breaking change) Three payloads in the experimental MCP installation and removal workflow are now sealed @@ -613,6 +682,19 @@ session.setAutoTier(null).get(); `setModel(SetModelOptions)` accepts the same preference through `SetModelOptions.setAutoTier(...)`, which stages the tier atomically with selecting `auto`. Call `setResetAutoTier(true)` instead to return to provider-default routing; the two options are mutually exclusive. +## Reasoning-summary presentation (experimental) + +Read the current model's reasoning-summary policy through `session.getRpc().model.getReasoningSummaries(...)`. Load the model catalog with `session.getRpc().model.list().get()` first, or accept a result with `ready() == false`. + +```java +import com.github.copilot.generated.rpc.SessionModelGetReasoningSummariesParams; + +var presentation = new SessionModelGetReasoningSummariesParams(null, false); +var policy = session.getRpc().model.getReasoningSummaries(presentation).get(); +``` + +The two constructor arguments are the persisted visibility setting (`null` when unset) and whether the host currently shows summaries (`null` defaults to false). The session wrapper supplies the session ID; callers do not need a placeholder ID. The original three-argument constructor remains available. `visibility()` can be `null` while experiment assignment is pending, and `clearRedundantSetting()` tells the host when its persisted setting matches the model default. + ## Session Store `enableSessionStore` on `SessionConfig` enables the cross-session store for search and retrieval across sessions. When unset in the default `CopilotClientMode.COPILOT_CLI` mode, the runtime default applies (enabled). In `CopilotClientMode.EMPTY` mode, defaults to disabled. @@ -875,7 +957,7 @@ CI enforces both checks. Spotless runs explicitly in CI; `mvn verify` alone does Run native-runtime Maven commands from the `java` directory. Native packaging requires Node.js in addition to JDK 25 and Maven. In a standalone SDK checkout, `copilot-native/scripts/fetch-native.mjs` retrieves the pinned runtime package from the corresponding GitHub release. When the SDK is nested in `copilot-agent-runtime`, it instead stages the same-checkout artifacts from `dist-cli`; run `pnpm run build:cli` from the runtime repository first. -On a native Linux glibc host, Maven activates `native-linux-x64` or `native-linux-arm64` for the matching architecture when `copilot.native.libc=glibc` is set. On a Linux musl x64 host, Maven activates `native-linuxmusl-x64` when `copilot.native.libc=musl` is set. On Windows x64, Windows ARM64, Intel macOS, and Apple Silicon macOS, Maven activates `native-win32-x64`, `native-win32-arm64`, `native-darwin-x64`, or `native-darwin-arm64` automatically. The matching profile validates the host, runs the native script tests, stages the platform package during `generate-resources`, packages the classifier JAR during `package`, and verifies its native contents. +On a native Linux glibc host, Maven activates `native-linux-x64` or `native-linux-arm64` for the matching architecture when `copilot.native.libc=glibc` is set. On a Linux musl host, Maven activates `native-linuxmusl-x64` or `native-linuxmusl-arm64` for the matching architecture when `copilot.native.libc=musl` is set. On Windows x64, Windows ARM64, Intel macOS, and Apple Silicon macOS, Maven activates `native-win32-x64`, `native-win32-arm64`, `native-darwin-x64`, or `native-darwin-arm64` automatically. The matching profile validates the host, runs the native script tests, stages the platform package during `generate-resources`, packages the classifier JAR during `package`, and verifies its native contents. Before opting in, validate that Node.js reports glibc for the build host: @@ -910,14 +992,14 @@ node copilot-native/scripts/validate-native-host.mjs linux-arm64 mvn -Pinprocess clean verify -Dcopilot.native.libc=glibc ``` -The same command validates in-process mode on Linux musl x64: +The same command validates in-process mode on Linux musl x64 or ARM64: ```bash -node copilot-native/scripts/validate-native-host.mjs linuxmusl-x64 +node copilot-native/scripts/validate-native-host.mjs linuxmusl-x64 # Use linuxmusl-arm64 on ARM64 mvn -Pinprocess clean verify -Dcopilot.native.libc=musl ``` -On Linux musl ARM64 and other unsupported hosts, do not set `copilot.native.libc`. A normal build produces only the OS-neutral primary, sources, and Javadoc JARs; it does not run native script tests, download or stage native files, or produce a platform classifier JAR. +On unsupported hosts, do not set `copilot.native.libc`. A normal build produces only the OS-neutral primary, sources, and Javadoc JARs; it does not run native script tests, download or stage native files, or produce a platform classifier JAR. To build only the OS-neutral artifacts on any host, or override the glibc opt-in, disable native download and packaging: diff --git a/java/copilot-native/pom.xml b/java/copilot-native/pom.xml index 2c750e4e47..41af2dd6cb 100644 --- a/java/copilot-native/pom.xml +++ b/java/copilot-native/pom.xml @@ -467,6 +467,64 @@ + + native-linuxmusl-arm64 + + + Linux + aarch64 + + + copilot.native.libc + musl + + + + linuxmusl-arm64 + + + + + org.codehaus.mojo + exec-maven-plugin + + + validate-native-host + validate + + + fetch-native + generate-resources + + + test-fetch-native + test + + + + + org.apache.maven.plugins + maven-jar-plugin + + + jar-native + package + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + verify-native-jars + package + + + + + + native-win32-x64 @@ -809,6 +867,68 @@ + + + attach-external-linuxmusl-arm64-classifier + + + copilot.native.external.linuxmusl.arm64.classifier.path + + + + + + org.codehaus.mojo + exec-maven-plugin + + + validate-external-linuxmusl-arm64-classifier + validate + + exec + + + node + + ${project.basedir}/scripts/validate-native-artifact.mjs + classifier + linuxmusl-arm64 + ${copilot.native.external.linuxmusl.arm64.classifier.path} + ${project.build.finalName}-linuxmusl-arm64.jar + ${copilot.sdk.root} + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-external-linuxmusl-arm64-classifier + package + + attach-artifact + + + + + ${copilot.native.external.linuxmusl.arm64.classifier.path} + jar + linuxmusl-arm64 + + + + + + + + + @@ -230,6 +230,27 @@ + + org.apache.maven.plugins + maven-dependency-plugin + 3.6.1 + + + packaged-consumer-dependencies + generate-test-resources + + copy-dependencies + + + ${maven.test.skip} + runtime + + jna + ${project.build.directory}/consumer-dependencies + + + + ${testExecutionAgentArgs} ${surefire.jvm.args} --add-opens com.github.copilot.java/com.github.copilot.e2e=ALL-UNNAMED - - 2 + 0 ${copilot.tests.dir} ${copilot.sdk.root} @@ -719,6 +732,22 @@ did not produce the multi-release output. Re-build on JDK 25+ and verify the linuxmusl-x64 + + native-linuxmusl-arm64 + + + Linux + aarch64 + + + copilot.native.libc + musl + + + + linuxmusl-arm64 + + native-win32-x64 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AiCreditsStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/AiCreditsStatus.java new file mode 100644 index 0000000000..f6f95a97a2 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AiCreditsStatus.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Whether the accumulated numeric AI-credit subtotal covers the observed calls. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum AiCreditsStatus { + /** The {@code complete} variant. */ + COMPLETE("complete"), + /** The {@code partial} variant. */ + PARTIAL("partial"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"); + + private final String value; + AiCreditsStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static AiCreditsStatus fromValue(String value) { + for (AiCreditsStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown AiCreditsStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseActivityEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseActivityEvent.java index 64d8d58283..832abb6e3d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseActivityEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseActivityEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "assistant.fusion_phase_activity". Experimental content-safe activity signal for a running HydraFusion phase. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class AssistantFusionPhaseActivityEvent extends SessionEvent { public void setData(AssistantFusionPhaseActivityEventData data) { this.data = data; } /** Data payload for {@link AssistantFusionPhaseActivityEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record AssistantFusionPhaseActivityEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseCompletedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseCompletedEvent.java index 27b144b281..e5d6804b5f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseCompletedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseCompletedEvent.java @@ -15,8 +15,11 @@ /** * Session event "assistant.fusion_phase_completed". Experimental durable HydraFusion phase output and lossless replay checkpoint. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class AssistantFusionPhaseCompletedEvent extends SessionEvent { public void setData(AssistantFusionPhaseCompletedEventData data) { this.data = data; } /** Data payload for {@link AssistantFusionPhaseCompletedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record AssistantFusionPhaseCompletedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseFailedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseFailedEvent.java index e248d0a9fe..45b850040c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseFailedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseFailedEvent.java @@ -15,8 +15,11 @@ /** * Session event "assistant.fusion_phase_failed". Experimental durable typed HydraFusion phase failure and degradation transition. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class AssistantFusionPhaseFailedEvent extends SessionEvent { public void setData(AssistantFusionPhaseFailedEventData data) { this.data = data; } /** Data payload for {@link AssistantFusionPhaseFailedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record AssistantFusionPhaseFailedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseStartedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseStartedEvent.java index 28ed76f283..a7efa03b82 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseStartedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantFusionPhaseStartedEvent.java @@ -15,8 +15,11 @@ /** * Session event "assistant.fusion_phase_started". Experimental transient HydraFusion phase/model/role signal. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class AssistantFusionPhaseStartedEvent extends SessionEvent { public void setData(AssistantFusionPhaseStartedEventData data) { this.data = data; } /** Data payload for {@link AssistantFusionPhaseStartedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record AssistantFusionPhaseStartedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantMessageEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantMessageEvent.java index 365b945965..87d0e6f29a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantMessageEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantMessageEvent.java @@ -42,6 +42,8 @@ public record AssistantMessageEventData( @JsonProperty("originatingMessageId") String originatingMessageId, /** Model that produced this assistant message, if known */ @JsonProperty("model") String model, + /** Opaque origin provider identity captured at dispatch. Only an exact match with the target provider permits replay of reasoningOpaque, encryptedContent, reasoningBlocks, serverTools, and provider response/item identifiers. Matching model ids or wire protocols is insufficient. Omitted for legacy or unattributed messages; the runtime excludes unproven opaque state when projecting to a known provider. Text content and client tool requests/results remain portable semantic history. */ + @JsonProperty("providerId") String providerId, /** The assistant's text response content */ @JsonProperty("content") String content, /** Tool invocations requested by the assistant in this message */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java index 0c02f5d15a..a392f290be 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java @@ -38,8 +38,16 @@ public final class AssistantUsageEvent extends SessionEvent { @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record AssistantUsageEventData( + /** Availability of this call's reported AI-credit amount. Missing billing is unavailable, not a zero charge. */ + @JsonProperty("aiCreditsStatus") AiCreditsStatus aiCreditsStatus, /** Model identifier used for this API call */ @JsonProperty("model") String model, + /** Provider identity and product label captured by the actual call's dispatch path. */ + @JsonProperty("provider") ModelProviderRef provider, + /** Model display name captured for this call, not derived from the current selection. */ + @JsonProperty("modelDisplayName") String modelDisplayName, + /** Runtime-owned identity shared with the durable accounting receipt. */ + @JsonProperty("accounting") UsageAccountingIdentity accounting, /** Number of input tokens consumed */ @JsonProperty("inputTokens") Long inputTokens, /** Number of output tokens produced */ @@ -89,6 +97,26 @@ public record AssistantUsageEventData( @JsonProperty("rejectedPredictionTokens") Long rejectedPredictionTokens, /** Transport used for this model call (http or websocket) */ @JsonProperty("transport") AssistantUsageTransport transport, + /** Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. */ + @JsonProperty("requestBodyBytes") Long requestBodyBytes, + /** Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. */ + @JsonProperty("requestBodyWireBytes") Long requestBodyWireBytes, + /** Content-Encoding applied to the request body of the attempt that produced this outcome; identity when uncompressed */ + @JsonProperty("requestBodyEncoding") ModelCallRequestBodyEncoding requestBodyEncoding, + /** Why the call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred */ + @JsonProperty("websocketFallbackReason") ModelCallWebSocketFallbackReason websocketFallbackReason, + /** Milliseconds spent on the WebSocket attempt before falling back to HTTP */ + @JsonProperty("websocketFallbackAfterMs") Long websocketFallbackAfterMs, + /** Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown */ + @JsonProperty("websocketFallbackErrorKind") ModelCallWebSocketFallbackErrorKind websocketFallbackErrorKind, + /** HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback */ + @JsonProperty("websocketFallbackStatusCode") Long websocketFallbackStatusCode, + /** WebSocket close code received before the HTTP fallback */ + @JsonProperty("websocketFallbackCloseCode") Long websocketFallbackCloseCode, + /** Whether a WebSocket reconnect was attempted before falling back to HTTP */ + @JsonProperty("websocketFallbackReconnectAttempted") Boolean websocketFallbackReconnectAttempted, + /** Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call */ + @JsonProperty("websocketFallbackStartedThisCall") Boolean websocketFallbackStartedThisCall, /** Completion ID from the model provider (e.g., chatcmpl-abc123) */ @JsonProperty("apiCallId") String apiCallId, /** GitHub request tracing ID (x-github-request-id header) for server-side log correlation */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AutoTier.java b/java/sdk/src/generated/java/com/github/copilot/generated/AutoTier.java index 1c9d81b8ed..b3669208d7 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AutoTier.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AutoTier.java @@ -10,30 +10,38 @@ import javax.annotation.processing.Generated; /** - * Routing preference used when the session model is `auto`. `fast` is an integrator-only latency preset and is not a first-party GitHub Copilot product preference. + * Extensible routing preference for the virtual `auto` model. New identifiers must be advertised and enabled by the provider. `fast` is an integrator-only latency preset. * * @since 1.0.0 */ @javax.annotation.processing.Generated("copilot-sdk-codegen") -public enum AutoTier { +public final class AutoTier { /** The {@code efficiency} variant. */ - EFFICIENCY("efficiency"), + public static final AutoTier EFFICIENCY = new AutoTier("efficiency"); /** The {@code balance} variant. */ - BALANCE("balance"), + public static final AutoTier BALANCE = new AutoTier("balance"); /** The {@code intelligence} variant. */ - INTELLIGENCE("intelligence"), + public static final AutoTier INTELLIGENCE = new AutoTier("intelligence"); /** The {@code fast} variant. */ - FAST("fast"); + public static final AutoTier FAST = new AutoTier("fast"); private final String value; - AutoTier(String value) { this.value = value; } + private AutoTier(String value) { this.value = value; } @com.fasterxml.jackson.annotation.JsonValue public String getValue() { return value; } @com.fasterxml.jackson.annotation.JsonCreator public static AutoTier fromValue(String value) { + if (value == null) return null; + if (value.isEmpty() || value.codePoints().anyMatch(c -> Character.isWhitespace(c) || Character.isISOControl(c))) + throw new IllegalArgumentException("AutoTier requires a routing identifier"); for (AutoTier v : values()) { if (v.value.equals(value)) return v; } - throw new IllegalArgumentException("Unknown AutoTier value: " + value); + return new AutoTier(value); } + /** Returns the known routing preferences. @return known values */ + public static AutoTier[] values() { return new AutoTier[] { EFFICIENCY, BALANCE, INTELLIGENCE, FAST }; } + @Override public boolean equals(Object other) { return other instanceof AutoTier v && value.equals(v.value); } + @Override public int hashCode() { return value.hashCode(); } + @Override public String toString() { return value; } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java b/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java index ed454deafd..cd6f610465 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java @@ -21,6 +21,14 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record CompactionCompleteCompactionTokensUsed( + /** Number of model requests represented by this aggregated compaction usage */ + @JsonProperty("requestCount") Long requestCount, + /** Whether the compaction's credit amount was reported for all, some, or none of its calls. */ + @JsonProperty("aiCreditsStatus") AiCreditsStatus aiCreditsStatus, + /** Provider captured for the compaction call; absent when attribution is unknown. */ + @JsonProperty("provider") ModelProviderRef provider, + /** Model display name captured for the compaction call. */ + @JsonProperty("modelDisplayName") String modelDisplayName, /** Input tokens consumed by the compaction LLM call */ @JsonProperty("inputTokens") Long inputTokens, /** Output tokens produced by the compaction LLM call */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPermissionsContext.java b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPermissionsContext.java new file mode 100644 index 0000000000..990ae9ace0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPermissionsContext.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Reusable managed permission evaluation context. Treat permissions as runtime-owned policy data and retain it verbatim; it includes source-aware composition metadata. This is a snapshot, not a capability or approval token; only use contexts obtained from trusted policy sources. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPermissionsContext( + /** Runtime-owned composed permissions object. Absent when no permission policy is configured. */ + @JsonProperty("permissions") Object permissions, + /** Policy could not be determined; evaluation must deny every operation. */ + @JsonProperty("failClosed") Boolean failClosed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPluginProgressPhase.java b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPluginProgressPhase.java new file mode 100644 index 0000000000..a1b2f401b5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPluginProgressPhase.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Current phase of organization-required plugin preparation. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ManagedPluginProgressPhase { + /** The {@code initializing} variant. */ + INITIALIZING("initializing"), + /** The {@code installing} variant. */ + INSTALLING("installing"), + /** The {@code updating} variant. */ + UPDATING("updating"), + /** The {@code complete} variant. */ + COMPLETE("complete"); + + private final String value; + ManagedPluginProgressPhase(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedPluginProgressPhase fromValue(String value) { + for (ManagedPluginProgressPhase v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedPluginProgressPhase value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ManagedSettingsEnforcedEscalation.java b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedSettingsEnforcedEscalation.java index 619fb326e1..ff4f36d055 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/ManagedSettingsEnforcedEscalation.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedSettingsEnforcedEscalation.java @@ -10,7 +10,7 @@ import javax.annotation.processing.Generated; /** - * For a `bypass_permissions_blocked` action, which permission-escalation primitive was refused + * For a `bypass_permissions_blocked` action, which permission-mode or escalation primitive was refused * * @since 1.0.0 */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/McpServerSource.java b/java/sdk/src/generated/java/com/github/copilot/generated/McpServerSource.java index 5ea2c39f51..2354c95750 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/McpServerSource.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/McpServerSource.java @@ -10,7 +10,7 @@ import javax.annotation.processing.Generated; /** - * Configuration source: user, workspace, plugin, builtin, or managed + * Configuration source: user, workspace, plugin, builtin, managed, or account * * @since 1.0.0 */ @@ -25,7 +25,9 @@ public enum McpServerSource { /** The {@code builtin} variant. */ BUILTIN("builtin"), /** The {@code managed} variant. */ - MANAGED("managed"); + MANAGED("managed"), + /** The {@code account} variant. */ + ACCOUNT("account"); private final String value; McpServerSource(String value) { this.value = value; } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java index 05e8a8371f..9bfa1cc686 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java @@ -60,6 +60,28 @@ public record ModelCallFailureEventData( @JsonProperty("transport") ModelCallFailureTransport transport, /** Whether the failure originated from an API response or the request transport */ @JsonProperty("failureKind") ModelCallFailureKind failureKind, + /** Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. */ + @JsonProperty("requestBodyBytes") Long requestBodyBytes, + /** Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. */ + @JsonProperty("requestBodyWireBytes") Long requestBodyWireBytes, + /** Content-Encoding applied to the failed request body; identity when uncompressed */ + @JsonProperty("requestBodyEncoding") ModelCallRequestBodyEncoding requestBodyEncoding, + /** Zero-based orchestrator retry index of the failed attempt */ + @JsonProperty("retryAttempt") Long retryAttempt, + /** Why the failed call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred */ + @JsonProperty("websocketFallbackReason") ModelCallWebSocketFallbackReason websocketFallbackReason, + /** Milliseconds spent on the WebSocket attempt before falling back to HTTP */ + @JsonProperty("websocketFallbackAfterMs") Long websocketFallbackAfterMs, + /** Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown */ + @JsonProperty("websocketFallbackErrorKind") ModelCallWebSocketFallbackErrorKind websocketFallbackErrorKind, + /** HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback */ + @JsonProperty("websocketFallbackStatusCode") Long websocketFallbackStatusCode, + /** WebSocket close code received before the HTTP fallback */ + @JsonProperty("websocketFallbackCloseCode") Long websocketFallbackCloseCode, + /** Whether a WebSocket reconnect was attempted before falling back to HTTP */ + @JsonProperty("websocketFallbackReconnectAttempted") Boolean websocketFallbackReconnectAttempted, + /** Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call */ + @JsonProperty("websocketFallbackStartedThisCall") Boolean websocketFallbackStartedThisCall, /** Effective maximum prompt-token limit for the failed call */ @JsonProperty("maxPromptTokens") Long maxPromptTokens, /** Effective maximum output-token limit for the failed call */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureRequestFingerprint.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureRequestFingerprint.java index b8d0622b6e..6e83338e11 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureRequestFingerprint.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureRequestFingerprint.java @@ -33,6 +33,12 @@ public record ModelCallFailureRequestFingerprint( @JsonProperty("imagePartCount") Long imagePartCount, /** Image parts whose media type cannot be determined (rejected by strict providers) */ @JsonProperty("imagePartsMissingMediaType") Long imagePartsMissingMediaType, + /** Summed byte length of inline image payloads (data URLs and base64 sources) */ + @JsonProperty("imageBytes") Long imageBytes, + /** Number of messages carrying opaque or encrypted reasoning */ + @JsonProperty("reasoningItemCount") Long reasoningItemCount, + /** Summed byte length of opaque or encrypted reasoning payloads */ + @JsonProperty("encryptedContentBytes") Long encryptedContentBytes, /** Role of the final message in the request */ @JsonProperty("lastMessageRole") String lastMessageRole ) { diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallRequestBodyEncoding.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallRequestBodyEncoding.java new file mode 100644 index 0000000000..ad1b96ad9d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallRequestBodyEncoding.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Content-Encoding applied to the request body sent on the wire + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ModelCallRequestBodyEncoding { + /** The {@code identity} variant. */ + IDENTITY("identity"), + /** The {@code gzip} variant. */ + GZIP("gzip"), + /** The {@code zstd} variant. */ + ZSTD("zstd"); + + private final String value; + ModelCallRequestBodyEncoding(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ModelCallRequestBodyEncoding fromValue(String value) { + for (ModelCallRequestBodyEncoding v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ModelCallRequestBodyEncoding value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackErrorKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackErrorKind.java new file mode 100644 index 0000000000..cb429a7d6d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackErrorKind.java @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Normalized cause of the WebSocket failure that triggered the HTTP fallback + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ModelCallWebSocketFallbackErrorKind { + /** The {@code dns} variant. */ + DNS("dns"), + /** The {@code tls} variant. */ + TLS("tls"), + /** The {@code timeout} variant. */ + TIMEOUT("timeout"), + /** The {@code connection_refused} variant. */ + CONNECTION_REFUSED("connection_refused"), + /** The {@code connection_reset} variant. */ + CONNECTION_RESET("connection_reset"), + /** The {@code closed_by_peer} variant. */ + CLOSED_BY_PEER("closed_by_peer"), + /** The {@code closed_locally} variant. */ + CLOSED_LOCALLY("closed_locally"), + /** The {@code not_connected} variant. */ + NOT_CONNECTED("not_connected"), + /** The {@code http_status} variant. */ + HTTP_STATUS("http_status"), + /** The {@code protocol} variant. */ + PROTOCOL("protocol"), + /** The {@code configuration} variant. */ + CONFIGURATION("configuration"), + /** The {@code other} variant. */ + OTHER("other"); + + private final String value; + ModelCallWebSocketFallbackErrorKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ModelCallWebSocketFallbackErrorKind fromValue(String value) { + for (ModelCallWebSocketFallbackErrorKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ModelCallWebSocketFallbackErrorKind value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackReason.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackReason.java new file mode 100644 index 0000000000..fc891ae508 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackReason.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Why a WebSocket-capable model call was carried by the HTTP fallback + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ModelCallWebSocketFallbackReason { + /** The {@code connect_failed} variant. */ + CONNECT_FAILED("connect_failed"), + /** The {@code connection_unavailable} variant. */ + CONNECTION_UNAVAILABLE("connection_unavailable"), + /** The {@code send_failed} variant. */ + SEND_FAILED("send_failed"), + /** The {@code api_error} variant. */ + API_ERROR("api_error"), + /** The {@code transport_failed} variant. */ + TRANSPORT_FAILED("transport_failed"); + + private final String value; + ModelCallWebSocketFallbackReason(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ModelCallWebSocketFallbackReason fromValue(String value) { + for (ModelCallWebSocketFallbackReason v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ModelCallWebSocketFallbackReason value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelProviderKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelProviderKind.java new file mode 100644 index 0000000000..cbef223e2b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelProviderKind.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The neutral kind of a model provider — the model analog of `AccountKind`. A model provider is the live, entitled source a model came from; central code never branches on this beyond a single dispatch. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ModelProviderKind { + /** The {@code copilot} variant. */ + COPILOT("copilot"), + /** The {@code loki} variant. */ + LOKI("loki"); + + private final String value; + ModelProviderKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ModelProviderKind fromValue(String value) { + for (ModelProviderKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ModelProviderKind value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelProviderRef.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelProviderRef.java new file mode 100644 index 0000000000..84a0fa8954 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelProviderRef.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A neutral reference to the model provider that produced a model: an opaque id, a human-readable label, and the provider kind. Carried on each enumerated Model so consumers can group by provider without reaching into a provider-shaped internal type. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ModelProviderRef( + /** Opaque, stable id of the provider that produced this model. Matches the enumerated `ModelProviderDescriptor.id`. */ + @JsonProperty("id") String id, + /** Human-readable provider label, owned by the runtime so every consumer renders identical text. */ + @JsonProperty("label") String label, + /** The provider kind. */ + @JsonProperty("kind") ModelProviderKind kind +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionAssentDetectedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionAssentDetectedEvent.java index 84ccf7473e..cd1b9c8c38 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionAssentDetectedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionAssentDetectedEvent.java @@ -15,8 +15,11 @@ /** * Session event "permission.assentDetected". Historical decode-only contextual-assent marker. Current runtimes do not project it into the conversation or permission flow. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class PermissionAssentDetectedEvent extends SessionEvent { public void setData(PermissionAssentDetectedEventData data) { this.data = data; } /** Data payload for {@link PermissionAssentDetectedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record PermissionAssentDetectedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionCarriedForwardEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionCarriedForwardEvent.java index e9126e2308..49061d7f4b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionCarriedForwardEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionCarriedForwardEvent.java @@ -15,8 +15,11 @@ /** * Session event "permission.carriedForward". Historical decode-only receipt from the retired Assisted Permissions authorization extractor. Current runtimes ignore it for permission decisions. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class PermissionCarriedForwardEvent extends SessionEvent { public void setData(PermissionCarriedForwardEventData data) { this.data = data; } /** Data payload for {@link PermissionCarriedForwardEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record PermissionCarriedForwardEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionContextualAuthorizationEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionContextualAuthorizationEvent.java index 80bc8cd24e..b7eea2dae2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionContextualAuthorizationEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionContextualAuthorizationEvent.java @@ -15,8 +15,11 @@ /** * Session event "permission.contextualAuthorization". Historical decode-only contextual authorization claim. Current runtimes preserve the payload but do not establish authority from it. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class PermissionContextualAuthorizationEvent extends SessionEvent { public void setData(PermissionContextualAuthorizationEventData data) { this.data = data; } /** Data payload for {@link PermissionContextualAuthorizationEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record PermissionContextualAuthorizationEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationDegradedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationDegradedEvent.java index dc49be3971..f793de8ad2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationDegradedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationDegradedEvent.java @@ -15,8 +15,11 @@ /** * Session event "permission.messageAuthorizationDegraded". Historical decode-only degradation marker from the retired extractor. Current runtimes ignore it for permission decisions. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class PermissionMessageAuthorizationDegradedEvent extends SessionEv public void setData(PermissionMessageAuthorizationDegradedEventData data) { this.data = data; } /** Data payload for {@link PermissionMessageAuthorizationDegradedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record PermissionMessageAuthorizationDegradedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationEvent.java index 88ff87b9dd..57254afaad 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationEvent.java @@ -16,8 +16,11 @@ /** * Session event "permission.messageAuthorization". Historical decode-only claim from the retired Assisted Permissions authorization extractor. Current runtimes preserve the payload but do not establish authority from it. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -33,6 +36,7 @@ public final class PermissionMessageAuthorizationEvent extends SessionEvent { public void setData(PermissionMessageAuthorizationEventData data) { this.data = data; } /** Data payload for {@link PermissionMessageAuthorizationEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record PermissionMessageAuthorizationEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationReadEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationReadEvent.java index b6fb8626bf..9415ee6d0d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationReadEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionMessageAuthorizationReadEvent.java @@ -15,8 +15,11 @@ /** * Session event "permission.messageAuthorizationRead". Historical decode-only extractor progress marker. Current runtimes do not run or resume extraction from it. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class PermissionMessageAuthorizationReadEvent extends SessionEvent public void setData(PermissionMessageAuthorizationReadEventData data) { this.data = data; } /** Data payload for {@link PermissionMessageAuthorizationReadEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record PermissionMessageAuthorizationReadEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java index ed38c3c168..796da04191 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java @@ -24,6 +24,10 @@ public record PermissionRecoveryData( /** Stable identifier shared by every transition in this recovery episode */ @JsonProperty("episodeId") String episodeId, + /** Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Current lifecycle state of the recovery episode */ @JsonProperty("status") PermissionRecoveryStatus status, /** Policy selected from the current client's response capability; mode or client changes may update it during recovery */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java index dd18d2af2e..5dbb6300af 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java @@ -44,6 +44,10 @@ public record PermissionRequestedEventData( @JsonProperty("permissionMode") PermissionMode permissionMode, /** Agent mode captured from the owning turn when permission evaluation began. */ @JsonProperty("agentMode") SessionMode agentMode, + /** Execution session that owns permission recovery for this request. Absent on historical events. */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Neutral risk metadata supplied by the tool host. Consumers may display this value but must not use it to bypass the permission decision. */ @JsonProperty("riskAssessment") Object riskAssessment, /** When true, this permission was already resolved by a permissionRequest hook and requires no client action */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsage.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsage.java new file mode 100644 index 0000000000..b0c3fdf5b6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsage.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * An authoritative monthly usage reading for the observation's provider, account, and service. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderMonthlyUsage( + /** Availability of monthly consumption. Missing or unavailable usage must never be interpreted as zero. */ + @JsonProperty("state") ProviderMonthlyUsageState state, + /** Unit of consumedQuantity; independent of the parent observation's balance unit. */ + @JsonProperty("unit") ProviderQuotaUnit unit, + /** Identity scope of the reading within its provider and service. */ + @JsonProperty("scope") ProviderMonthlyUsageScope scope, + /** Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. */ + @JsonProperty("consumedQuantity") Double consumedQuantity, + /** Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. */ + @JsonProperty("queriedAt") String queriedAt, + /** Start of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("cycleStart") String cycleStart, + /** End of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("resetOn") String resetOn +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageScope.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageScope.java new file mode 100644 index 0000000000..fb61e9283e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageScope.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Identity scope of a monthly usage reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageScope { + /** The {@code user} variant. */ + USER("user"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageScope(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageScope fromValue(String value) { + for (ProviderMonthlyUsageScope v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageScope value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageState.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageState.java new file mode 100644 index 0000000000..27df08fdb1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageState.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Availability of a service's monthly consumption reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageState { + /** The {@code available} variant. */ + AVAILABLE("available"), + /** The {@code no_policy} variant. */ + NO_POLICY("no_policy"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageState fromValue(String value) { + for (ProviderMonthlyUsageState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaAccessState.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaAccessState.java new file mode 100644 index 0000000000..e9d9ef966e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaAccessState.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Access policy reported by the quota service. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaAccessState { + /** The {@code allowed} variant. */ + ALLOWED("allowed"), + /** The {@code denied} variant. */ + DENIED("denied"), + /** The {@code not_required} variant. */ + NOT_REQUIRED("not_required"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"); + + private final String value; + ProviderQuotaAccessState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaAccessState fromValue(String value) { + for (ProviderQuotaAccessState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaAccessState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaAcquisitionStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaAcquisitionStatus.java new file mode 100644 index 0000000000..0b2c8aaa51 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaAcquisitionStatus.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Acquisition state, independent of the service's business access/capacity verdict. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaAcquisitionStatus { + /** The {@code succeeded} variant. */ + SUCCEEDED("succeeded"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"), + /** The {@code failed} variant. */ + FAILED("failed"); + + private final String value; + ProviderQuotaAcquisitionStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaAcquisitionStatus fromValue(String value) { + for (ProviderQuotaAcquisitionStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaAcquisitionStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaBudgetMetadata.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaBudgetMetadata.java new file mode 100644 index 0000000000..c32d10903d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaBudgetMetadata.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Authoritative budget measurements and policy metadata, independent of provider. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderQuotaBudgetMetadata( + /** Whether the budget has unlimited entitlement. */ + @JsonProperty("unlimited") Boolean unlimited, + /** Exact budget entitlement, retaining incumbent fractional-unit compatibility. */ + @JsonProperty("entitlement") Double entitlement, + /** Exact measured consumption in the budget's unit. */ + @JsonProperty("consumed") Double consumed, + /** Service-reported remaining percentage for authoritative budget presentation. */ + @JsonProperty("remainingPercentage") Double remainingPercentage, + /** Whether service policy allows continued usage after exhaustion. */ + @JsonProperty("usageAllowedWhenExhausted") Boolean usageAllowedWhenExhausted, + /** Usage beyond entitlement, in the budget's unit. */ + @JsonProperty("overage") Double overage, + /** Whether additional usage is allowed when the budget is exhausted. */ + @JsonProperty("overageAllowedWhenExhausted") Boolean overageAllowedWhenExhausted, + /** Reset instant in epoch milliseconds when this budget actually defines a window. */ + @JsonProperty("resetAtEpochMs") Double resetAtEpochMs, + /** Whether the reset instant is an estimate. */ + @JsonProperty("resetEstimated") Boolean resetEstimated, + /** Whether this budget uses token-based billing. */ + @JsonProperty("tokenBasedBilling") Boolean tokenBasedBilling, + /** Optional additional-usage budget cap. */ + @JsonProperty("overageLimit") Double overageLimit +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaCapacityState.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaCapacityState.java new file mode 100644 index 0000000000..590168d881 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaCapacityState.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Capacity is independent of whether a numeric balance was supplied. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaCapacityState { + /** The {@code available} variant. */ + AVAILABLE("available"), + /** The {@code exhausted} variant. */ + EXHAUSTED("exhausted"), + /** The {@code unlimited} variant. */ + UNLIMITED("unlimited"), + /** The {@code not_required} variant. */ + NOT_REQUIRED("not_required"), + /** The {@code not_applicable} variant. */ + NOT_APPLICABLE("not_applicable"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"); + + private final String value; + ProviderQuotaCapacityState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaCapacityState fromValue(String value) { + for (ProviderQuotaCapacityState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaCapacityState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaObservationKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaObservationKind.java new file mode 100644 index 0000000000..adc6826ebe --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaObservationKind.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Timing and purpose of a provider quota observation. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaObservationKind { + /** The {@code account_snapshot} variant. */ + ACCOUNT_SNAPSHOT("account_snapshot"), + /** The {@code admission_state} variant. */ + ADMISSION_STATE("admission_state"); + + private final String value; + ProviderQuotaObservationKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaObservationKind fromValue(String value) { + for (ProviderQuotaObservationKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaObservationKind value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaQuantityKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaQuantityKind.java new file mode 100644 index 0000000000..44f2509f0c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaQuantityKind.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Interpretation permitted for independently reported quantities. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaQuantityKind { + /** The {@code authoritative_budget} variant. */ + AUTHORITATIVE_BUDGET("authoritative_budget"), + /** The {@code advisory_balance} variant. */ + ADVISORY_BALANCE("advisory_balance"), + /** The {@code none} variant. */ + NONE("none"); + + private final String value; + ProviderQuotaQuantityKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaQuantityKind fromValue(String value) { + for (ProviderQuotaQuantityKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaQuantityKind value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaState.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaState.java new file mode 100644 index 0000000000..6beeefee69 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaState.java @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * An account quota reading. Absence of a quantity is unknown, never zero. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderQuotaState( + /** Provider/account whose service reported this state. */ + @JsonProperty("provider") ModelProviderRef provider, + /** Service-owned quota identifier within this provider. */ + @JsonProperty("quotaId") String quotaId, + /** Unit of entitledQuantity and availableQuantity. */ + @JsonProperty("unit") ProviderQuotaUnit unit, + /** Whether the service permits access, independently of balance. */ + @JsonProperty("accessState") ProviderQuotaAccessState accessState, + /** Service capacity state; missing quantities do not imply exhaustion. */ + @JsonProperty("capacityState") ProviderQuotaCapacityState capacityState, + /** Whether this is a GET account reading or a pre-response admission observation. Observations are never merged across kinds. */ + @JsonProperty("observationKind") ProviderQuotaObservationKind observationKind, + /** Whether quantities are authoritative budget measurements, advisory balances, or absent. Only authoritative budgets support percentage presentation. */ + @JsonProperty("quantityKind") ProviderQuotaQuantityKind quantityKind, + /** Acquisition outcome. Unavailable/failed readings have no service verdict; access/capacity unavailable are compatibility placeholders only. */ + @JsonProperty("acquisitionStatus") ProviderQuotaAcquisitionStatus acquisitionStatus, + /** When the runtime observed this reading, not a charge timestamp or guarantee that consumption has settled. */ + @JsonProperty("observedAt") String observedAt, + /** HTTP status from acquisition, when available. */ + @JsonProperty("httpStatus") Long httpStatus, + /** Service error code or client acquisition category, separate from the business-state reason. */ + @JsonProperty("acquisitionError") String acquisitionError, + /** Optional metadata for an authoritative budget. Advisory balances and admission-only observations do not populate this. */ + @JsonProperty("budgetMetadata") ProviderQuotaBudgetMetadata budgetMetadata, + /** Service-reported monthly consumption, independent of quota balances and per-call or session cost. Omitted when the service does not report monthly usage. */ + @JsonProperty("monthlyUsage") ProviderMonthlyUsage monthlyUsage, + /** Key for the backwards-compatible snapshots projection, when the authoritative budget supports that contract. */ + @JsonProperty("compatibilityKey") String compatibilityKey, + /** Explicit service admission flag, when reported. */ + @JsonProperty("hasQuota") Boolean hasQuota, + /** Independently reported signed 64-bit entitlement. -1 is an unlimited sentinel, not a capacity-state rewrite; omission and null are preserved. */ + @JsonProperty("entitledQuantity") Long entitledQuantity, + /** Independently reported signed 64-bit available quantity. Zero does not override the service access/capacity verdict; omission and null are preserved. */ + @JsonProperty("availableQuantity") Long availableQuantity, + /** Service-reported explanation for the state. */ + @JsonProperty("reason") String reason, + /** Service-reported quota source. */ + @JsonProperty("source") String source, + /** Service name owning this reading. */ + @JsonProperty("service") String service +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaUnit.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaUnit.java new file mode 100644 index 0000000000..d8dc0048d7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaUnit.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Units explicitly reported by a quota provider. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaUnit { + /** The {@code ai_credits} variant. */ + AI_CREDITS("ai_credits"), + /** The {@code requests} variant. */ + REQUESTS("requests"), + /** The {@code tokens} variant. */ + TOKENS("tokens"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderQuotaUnit(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaUnit fromValue(String value) { + for (ProviderQuotaUnit v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaUnit value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/RecommendedAutoTier.java b/java/sdk/src/generated/java/com/github/copilot/generated/RecommendedAutoTier.java index acccaf5c8e..748395b847 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/RecommendedAutoTier.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/RecommendedAutoTier.java @@ -10,28 +10,36 @@ import javax.annotation.processing.Generated; /** - * Auto preferences that Copilot API can recommend. + * Enabled Auto preferences that Copilot API can recommend. * * @since 1.0.0 */ @javax.annotation.processing.Generated("copilot-sdk-codegen") -public enum RecommendedAutoTier { +public final class RecommendedAutoTier { /** The {@code efficiency} variant. */ - EFFICIENCY("efficiency"), + public static final RecommendedAutoTier EFFICIENCY = new RecommendedAutoTier("efficiency"); /** The {@code balance} variant. */ - BALANCE("balance"), + public static final RecommendedAutoTier BALANCE = new RecommendedAutoTier("balance"); /** The {@code intelligence} variant. */ - INTELLIGENCE("intelligence"); + public static final RecommendedAutoTier INTELLIGENCE = new RecommendedAutoTier("intelligence"); private final String value; - RecommendedAutoTier(String value) { this.value = value; } + private RecommendedAutoTier(String value) { this.value = value; } @com.fasterxml.jackson.annotation.JsonValue public String getValue() { return value; } @com.fasterxml.jackson.annotation.JsonCreator public static RecommendedAutoTier fromValue(String value) { + if (value == null) return null; + if (value.isEmpty() || value.codePoints().anyMatch(c -> Character.isWhitespace(c) || Character.isISOControl(c))) + throw new IllegalArgumentException("RecommendedAutoTier requires a routing identifier"); for (RecommendedAutoTier v : values()) { if (v.value.equals(value)) return v; } - throw new IllegalArgumentException("Unknown RecommendedAutoTier value: " + value); + return new RecommendedAutoTier(value); } + /** Returns the known routing preferences. @return known values */ + public static RecommendedAutoTier[] values() { return new RecommendedAutoTier[] { EFFICIENCY, BALANCE, INTELLIGENCE }; } + @Override public boolean equals(Object other) { return other instanceof RecommendedAutoTier v && value.equals(v.value); } + @Override public int hashCode() { return value.hashCode(); } + @Override public String toString() { return value; } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java b/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java index 5fba9dfc33..f009f516f1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java @@ -25,7 +25,9 @@ public enum RemediationAction { /** The {@code review_sandbox_policy} variant. */ REVIEW_SANDBOX_POLICY("review_sandbox_policy"), /** The {@code allow_sandbox_outbound} variant. */ - ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"); + ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"), + /** The {@code rewind_conversation} variant. */ + REWIND_CONVERSATION("rewind_conversation"); private final String value; RemediationAction(String value) { this.value = value; } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoModeResolvedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoModeResolvedEvent.java index ba26c98c2e..f2d8a33293 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoModeResolvedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoModeResolvedEvent.java @@ -10,14 +10,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.List; import java.util.Map; import javax.annotation.processing.Generated; /** * Session event "session.auto_mode_resolved". Auto Intent resolution: the concrete model the session settled on for the first prompt of an auto-mode session, and why. Lets SDK clients render the chosen model and the full reason it was picked. The core selection fields (chosenModel/reasoningBucket/categoryScores) are stable; the routing-analytics fields (predictedLabel/confidence/candidateModels) mirror the upstream intent service and may evolve, hence the event's experimental stability. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -33,6 +37,7 @@ public final class SessionAutoModeResolvedEvent extends SessionEvent { public void setData(SessionAutoModeResolvedEventData data) { this.data = data; } /** Data payload for {@link SessionAutoModeResolvedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionAutoModeResolvedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoTierRecommendationEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoTierRecommendationEvent.java index 9dd00a4586..5846359232 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoTierRecommendationEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionAutoTierRecommendationEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.auto_tier_recommendation". Live-only Auto preference recommendation from Copilot API after a successful Auto model call. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionAutoTierRecommendationEvent extends SessionEvent { public void setData(SessionAutoTierRecommendationEventData data) { this.data = data; } /** Data payload for {@link SessionAutoTierRecommendationEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionAutoTierRecommendationEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionBinaryAssetEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionBinaryAssetEvent.java index e925f2320a..d5e7a3f13f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionBinaryAssetEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionBinaryAssetEvent.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.Map; import javax.annotation.processing.Generated; /** * Session event "session.binary_asset". Canonical bytes for a content-addressed binary asset shared by reference across events + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +36,7 @@ public final class SessionBinaryAssetEvent extends SessionEvent { public void setData(SessionBinaryAssetEventData data) { this.data = data; } /** Data payload for {@link SessionBinaryAssetEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionBinaryAssetEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasClosedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasClosedEvent.java index b660c0be66..b21bed7393 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasClosedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasClosedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.canvas.closed". Payload of `session.canvas.closed` with the closed canvas instance ID, provider ID, and canvas ID. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionCanvasClosedEvent extends SessionEvent { public void setData(SessionCanvasClosedEventData data) { this.data = data; } /** Data payload for {@link SessionCanvasClosedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionCanvasClosedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasOpenedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasOpenedEvent.java index 018e6a234d..fc371c2c59 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasOpenedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasOpenedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.canvas.opened". Payload of `session.canvas.opened` with canvas instance and provider IDs plus optional icon, title, status, URL, and input. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionCanvasOpenedEvent extends SessionEvent { public void setData(SessionCanvasOpenedEventData data) { this.data = data; } /** Data payload for {@link SessionCanvasOpenedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionCanvasOpenedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRecordedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRecordedEvent.java index 6f2fb42594..a2bcb80ce4 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRecordedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRecordedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.canvas.recorded". Durable record that a canvas instance is open, used to restore open canvases on cold session resume. Intentionally omits the transient url and availability. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionCanvasRecordedEvent extends SessionEvent { public void setData(SessionCanvasRecordedEventData data) { this.data = data; } /** Data payload for {@link SessionCanvasRecordedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionCanvasRecordedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRegistryChangedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRegistryChangedEvent.java index 0a6a9b62de..d97ef0ad95 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRegistryChangedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRegistryChangedEvent.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.List; import javax.annotation.processing.Generated; /** * Session event "session.canvas.registry_changed". Payload of `session.canvas.registry_changed` listing the canvas declarations currently available. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +36,7 @@ public final class SessionCanvasRegistryChangedEvent extends SessionEvent { public void setData(SessionCanvasRegistryChangedEventData data) { this.data = data; } /** Data payload for {@link SessionCanvasRegistryChangedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionCanvasRegistryChangedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRemovedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRemovedEvent.java index cea7ab09af..30181c1f13 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRemovedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasRemovedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.canvas.removed". Durable record that a canvas instance was closed, superseding a prior instance_recorded during resume replay. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionCanvasRemovedEvent extends SessionEvent { public void setData(SessionCanvasRemovedEventData data) { this.data = data; } /** Data payload for {@link SessionCanvasRemovedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionCanvasRemovedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasUnavailableEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasUnavailableEvent.java index 4e4397ecb6..5ff62e59b7 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasUnavailableEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCanvasUnavailableEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.canvas.unavailable". Transient signal that an open canvas instance's provider has dropped (for example the extension is reloading mid-session). The host should keep the panel mounted and surface a reconnecting affordance rather than tearing it down; a subsequent `session.canvas.opened` for the same instanceId clears the affordance once the provider reconnects with a fresh url. Ephemeral and never persisted, so it is never replayed on cold resume. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionCanvasUnavailableEvent extends SessionEvent { public void setData(SessionCanvasUnavailableEventData data) { this.data = data; } /** Data payload for {@link SessionCanvasUnavailableEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionCanvasUnavailableEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCompletionReceiptEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCompletionReceiptEvent.java index 15670c992a..ef6ad4eef1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionCompletionReceiptEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionCompletionReceiptEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.completion_receipt". Behavior-neutral record of structured runtime facts present when an agent completion decision is accepted. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionCompletionReceiptEvent extends SessionEvent { public void setData(SessionCompletionReceiptEventData data) { this.data = data; } /** Data payload for {@link SessionCompletionReceiptEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionCompletionReceiptEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java index 3ef32dfd13..9c6af84ab2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java @@ -34,10 +34,14 @@ public final class SessionErrorEvent extends SessionEvent { @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionErrorEventData( - /** Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") */ + /** Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query") */ @JsonProperty("errorType") String errorType, /** Fine-grained error code from the upstream provider, when available. For `errorType: "rate_limit"`, this is one of the `RateLimitErrorCode` values (e.g., `"user_weekly_rate_limited"`, `"user_global_rate_limited"`, `"rate_limited"`, `"user_model_rate_limited"`, `"integration_rate_limited"`). For `errorType: "quota"`, this is the CAPI quota error code (e.g., `"quota_exceeded"`, `"session_quota_exceeded"`, `"billing_not_configured"`). */ @JsonProperty("errorCode") String errorCode, + /** Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). */ + @JsonProperty("providerErrorType") String providerErrorType, + /** Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. */ + @JsonProperty("providerErrorParam") String providerErrorParam, /** Only set on `errorType: "rate_limit"`. When `true`, the runtime will follow this error with an `auto_mode_switch.requested` event (or silently switch if `continueOnAutoMode` is enabled). UI clients can use this flag to suppress duplicate rendering of the rate-limit error when they show their own auto-mode-switch prompt. */ @JsonProperty("eligibleForAutoSwitch") Boolean eligibleForAutoSwitch, /** Human-readable error message */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionEvent.java index 726dd21975..563b8c6e6b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionEvent.java @@ -54,6 +54,7 @@ @JsonSubTypes.Type(value = SessionSnapshotRewindEvent.class, name = "session.snapshot_rewind"), @JsonSubTypes.Type(value = SessionShutdownEvent.class, name = "session.shutdown"), @JsonSubTypes.Type(value = SessionUsageCheckpointEvent.class, name = "session.usage_checkpoint"), + @JsonSubTypes.Type(value = SessionQuotaObservationEvent.class, name = "session.quota_observation"), @JsonSubTypes.Type(value = SessionContextChangedEvent.class, name = "session.context_changed"), @JsonSubTypes.Type(value = SessionUsageInfoEvent.class, name = "session.usage_info"), @JsonSubTypes.Type(value = SessionContextClearedEvent.class, name = "session.context_cleared"), @@ -147,6 +148,7 @@ @JsonSubTypes.Type(value = SessionLimitsExhaustedRequestedEvent.class, name = "session_limits_exhausted.requested"), @JsonSubTypes.Type(value = SessionLimitsExhaustedCompletedEvent.class, name = "session_limits_exhausted.completed"), @JsonSubTypes.Type(value = SessionAutoModeResolvedEvent.class, name = "session.auto_mode_resolved"), + @JsonSubTypes.Type(value = SessionManagedPluginProgressEvent.class, name = "session.managed_plugin_progress"), @JsonSubTypes.Type(value = SessionManagedSettingsResolvedEvent.class, name = "session.managed_settings_resolved"), @JsonSubTypes.Type(value = SessionManagedSettingsEnforcedEvent.class, name = "session.managed_settings_enforced"), @JsonSubTypes.Type(value = CommandsChangedEvent.class, name = "commands.changed"), @@ -209,6 +211,7 @@ public abstract sealed class SessionEvent permits SessionSnapshotRewindEvent, SessionShutdownEvent, SessionUsageCheckpointEvent, + SessionQuotaObservationEvent, SessionContextChangedEvent, SessionUsageInfoEvent, SessionContextClearedEvent, @@ -302,6 +305,7 @@ public abstract sealed class SessionEvent permits SessionLimitsExhaustedRequestedEvent, SessionLimitsExhaustedCompletedEvent, SessionAutoModeResolvedEvent, + SessionManagedPluginProgressEvent, SessionManagedSettingsResolvedEvent, SessionManagedSettingsEnforcedEvent, CommandsChangedEvent, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionCompletedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionCompletedEvent.java index 6742cdc3e3..3adc227a1c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionCompletedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionCompletedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.fusion_completed". Experimental durable aggregate outcome of a HydraFusion turn. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionFusionCompletedEvent extends SessionEvent { public void setData(SessionFusionCompletedEventData data) { this.data = data; } /** Data payload for {@link SessionFusionCompletedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionFusionCompletedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionResolvedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionResolvedEvent.java index 44ef8be4ab..20ef8aad9f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionResolvedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionResolvedEvent.java @@ -16,8 +16,11 @@ /** * Session event "session.fusion_resolved". Experimental durable validated HydraFusion route and turn policy. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -33,6 +36,7 @@ public final class SessionFusionResolvedEvent extends SessionEvent { public void setData(SessionFusionResolvedEventData data) { this.data = data; } /** Data payload for {@link SessionFusionResolvedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionFusionResolvedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteFailedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteFailedEvent.java index 25698b336b..eac6892f56 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteFailedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteFailedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.fusion_route_failed". Experimental durable HydraFusion routing failure and the deterministic concrete fallback selected for the turn. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionFusionRouteFailedEvent extends SessionEvent { public void setData(SessionFusionRouteFailedEventData data) { this.data = data; } /** Data payload for {@link SessionFusionRouteFailedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionFusionRouteFailedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteStartedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteStartedEvent.java index 139cb4f011..f8d350535e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteStartedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionFusionRouteStartedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "session.fusion_route_started". Experimental transient signal that HydraFusion routing has started for an eligible turn. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SessionFusionRouteStartedEvent extends SessionEvent { public void setData(SessionFusionRouteStartedEventData data) { this.data = data; } /** Data payload for {@link SessionFusionRouteStartedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionFusionRouteStartedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedPluginProgressEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedPluginProgressEvent.java new file mode 100644 index 0000000000..f812f0fdcd --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedPluginProgressEvent.java @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Session event "session.managed_plugin_progress". Experimental transient presentation-neutral progress for organization-required plugin preparation. Clients should localize the phase copy and display plugin specs without translating them. + * + * @apiNote This event type is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionManagedPluginProgressEvent extends SessionEvent { + + @Override + public String getType() { return "session.managed_plugin_progress"; } + + @JsonProperty("data") + private SessionManagedPluginProgressEventData data; + + public SessionManagedPluginProgressEventData getData() { return data; } + public void setData(SessionManagedPluginProgressEventData data) { this.data = data; } + + /** Data payload for {@link SessionManagedPluginProgressEvent}. */ + @CopilotExperimental + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionManagedPluginProgressEventData( + /** Current preparation phase. */ + @JsonProperty("phase") ManagedPluginProgressPhase phase, + /** Ordered plugin install specs affected by this phase. Empty while managed settings initialize and when preparation completes. */ + @JsonProperty("pluginSpecs") List pluginSpecs + ) { + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsEnforcedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsEnforcedEvent.java index c712a220a9..2017f32e84 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsEnforcedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsEnforcedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** - * Session event "session.managed_settings_enforced". Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on a bypass-permissions escalation while policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. + * Session event "session.managed_settings_enforced". Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on bypass permissions or Assisted Permissions while the corresponding policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,14 +35,15 @@ public final class SessionManagedSettingsEnforcedEvent extends SessionEvent { public void setData(SessionManagedSettingsEnforcedEventData data) { this.data = data; } /** Data payload for {@link SessionManagedSettingsEnforcedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionManagedSettingsEnforcedEventData( /** The category of runtime action that managed policy governed. */ @JsonProperty("action") ManagedSettingsEnforcedAction action, - /** For a `bypass_permissions_blocked` action, which permission-escalation primitive was refused. Absent for actions without a specific escalation primitive. */ + /** For a `bypass_permissions_blocked` action, which permission-mode or escalation primitive was refused. Absent for actions without a specific primitive. */ @JsonProperty("escalation") ManagedSettingsEnforcedEscalation escalation, - /** The managed setting key responsible for the enforcement (e.g. `permissions.disableBypassPermissionsMode`). */ + /** The managed setting key responsible for the enforcement (for example `permissions.disableBypassPermissionsMode` or `permissions.disableAssistedPermissionsMode`). */ @JsonProperty("setting") String setting, /** Whether the enforcement was forced by fail-closed handling (managed policy could not be determined) rather than an explicit managed setting. When true, `setting` still names the restriction that was applied. */ @JsonProperty("failClosed") Boolean failClosed, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java index d495ec8cf6..007e911ef8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.List; import javax.annotation.processing.Generated; /** * Session event "session.managed_settings_resolved". Effective enterprise managed settings applied to the session and their contributing channels. Emitted whenever managed policy is applied or reapplied, including session start, resume, and account switch. This ephemeral live snapshot is delivered to subscribers but not persisted to the session event log; initial resolution occurs before session.start. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,9 +36,12 @@ public final class SessionManagedSettingsResolvedEvent extends SessionEvent { public void setData(SessionManagedSettingsResolvedEventData data) { this.data = data; } /** Data payload for {@link SessionManagedSettingsResolvedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionManagedSettingsResolvedEventData( + /** Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. */ @JsonProperty("source") ManagedSettingsResolvedSource source, /** Whether the server (account/org) managed-settings layer was present */ @@ -45,11 +52,11 @@ public record SessionManagedSettingsResolvedEventData( @JsonProperty("clientManaged") Boolean clientManaged, /** Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. */ @JsonProperty("policyHelperManaged") Boolean policyHelperManaged, - /** Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. */ + /** Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. */ @JsonProperty("failClosed") Boolean failClosed, /** Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. */ @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, - /** Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. */ + /** Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. */ @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, /** Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. */ @JsonProperty("permissionsAllowIntersected") Boolean permissionsAllowIntersected, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionModelChangeEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionModelChangeEvent.java index 09e39c584d..c6de1f0246 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionModelChangeEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionModelChangeEvent.java @@ -38,12 +38,18 @@ public record SessionModelChangeEventData( @JsonProperty("previousModel") String previousModel, /** Newly selected model identifier */ @JsonProperty("newModel") String newModel, + /** Provider selected for newModel. Omitted for legacy or unattributed selections; never inferred from a later selection. */ + @JsonProperty("providerId") String providerId, + /** Provider of previousModel, when known. A provider-only change is a model selection change even when the model identifiers are equal. */ + @JsonProperty("previousProviderId") String previousProviderId, /** Reasoning effort level before the model change, if applicable */ @JsonProperty("previousReasoningEffort") String previousReasoningEffort, /** Reasoning effort level after the model change, if applicable */ @JsonProperty("reasoningEffort") String reasoningEffort, /** Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. */ @JsonProperty("reasoningEffortModel") String reasoningEffortModel, + /** True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. */ + @JsonProperty("reasoningEffortManaged") Boolean reasoningEffortManaged, /** Reasoning summary mode before the model change, if applicable */ @JsonProperty("previousReasoningSummary") ReasoningSummary previousReasoningSummary, /** Reasoning summary mode after the model change, if applicable */ @@ -54,6 +60,8 @@ public record SessionModelChangeEventData( @JsonProperty("verbosity") Verbosity verbosity, /** Context tier after the model change; null explicitly clears a previously selected tier */ @JsonProperty("contextTier") ContextTier contextTier, + /** True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. */ + @JsonProperty("contextTierManaged") Boolean contextTierManaged, /** Reason the change happened, when not user-initiated. `"rate_limit_auto_switch"` for changes triggered by the auto-mode-switch rate-limit recovery path, or `"refusal_fallback"` when the active model declined a request (content refusal) and the runtime switched to the configured refusal-fallback model. UI clients can use this to render contextual copy. */ @JsonProperty("cause") String cause, /** Origin of the effective model change, when known. */ @@ -61,7 +69,31 @@ public record SessionModelChangeEventData( /** Previously committed Auto preference, when one was explicitly selected. */ @JsonProperty("previousAutoTier") AutoTier previousAutoTier, /** Committed Auto preference after the model configuration change, when applicable. */ - @JsonProperty("autoTier") AutoTier autoTier + @JsonProperty("autoTier") AutoTier autoTier, + /** True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. */ + @JsonProperty("autoTierManaged") Boolean autoTierManaged ) { + + /** + * Creates event data with the components it had before later optional fields were added. + */ + public SessionModelChangeEventData( + String previousModel, + String newModel, + String previousReasoningEffort, + String reasoningEffort, + String reasoningEffortModel, + ReasoningSummary previousReasoningSummary, + ReasoningSummary reasoningSummary, + Verbosity previousVerbosity, + Verbosity verbosity, + ContextTier contextTier, + String cause, + ModelChangeSource source, + AutoTier previousAutoTier, + AutoTier autoTier + ) { + this(previousModel, newModel, null, null, previousReasoningEffort, reasoningEffort, reasoningEffortModel, null, previousReasoningSummary, reasoningSummary, previousVerbosity, verbosity, contextTier, null, cause, source, previousAutoTier, autoTier, null); + } } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java index 56d08f53b4..262bf4578d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java @@ -37,6 +37,10 @@ public final class SessionPermissionRecoveryEvent extends SessionEvent { public record SessionPermissionRecoveryEventData( /** Stable identifier shared by every transition in this recovery episode */ @JsonProperty("episodeId") String episodeId, + /** Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Current lifecycle state of the recovery episode */ @JsonProperty("status") PermissionRecoveryStatus status, /** Policy selected from the current client's response capability; mode or client changes may update it during recovery */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionsChangedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionsChangedEvent.java index 5d45858942..818efd8527 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionsChangedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionsChangedEvent.java @@ -15,8 +15,11 @@ /** * Session event "session.permissions_changed". Permission-mode transition details. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +35,7 @@ public final class SessionPermissionsChangedEvent extends SessionEvent { public void setData(SessionPermissionsChangedEventData data) { this.data = data; } /** Data payload for {@link SessionPermissionsChangedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionPermissionsChangedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionQuotaObservationEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionQuotaObservationEvent.java new file mode 100644 index 0000000000..00f710af94 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionQuotaObservationEvent.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Session event "session.quota_observation". A provider-owned quota observation, distinct from per-call usage and charge accounting. + * + * @apiNote This event type is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionQuotaObservationEvent extends SessionEvent { + + @Override + public String getType() { return "session.quota_observation"; } + + @JsonProperty("data") + private SessionQuotaObservationEventData data; + + public SessionQuotaObservationEventData getData() { return data; } + public void setData(SessionQuotaObservationEventData data) { this.data = data; } + + /** Data payload for {@link SessionQuotaObservationEvent}. */ + @CopilotExperimental + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record SessionQuotaObservationEventData( + /** The admitted provider's state observation. Admission balances and percentages remain absent; separate monthly usage may report its own amount and cycle. */ + @JsonProperty("observation") ProviderQuotaState observation + ) { + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionResumeEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionResumeEvent.java index 4120d9e7c8..1020ae8195 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionResumeEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionResumeEvent.java @@ -43,18 +43,26 @@ public record SessionResumeEventData( @JsonProperty("eventsFileSizeBytes") Long eventsFileSizeBytes, /** Model currently selected at resume time */ @JsonProperty("selectedModel") String selectedModel, + /** Provider of selectedModel at resume time, when explicitly selected. */ + @JsonProperty("providerId") String providerId, /** Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max") */ @JsonProperty("reasoningEffort") String reasoningEffort, /** Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. */ @JsonProperty("reasoningEffortModel") String reasoningEffortModel, + /** True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. */ + @JsonProperty("reasoningEffortManaged") Boolean reasoningEffortManaged, /** Reasoning summary mode used for model calls, if applicable (e.g. "none", "concise", "detailed") */ @JsonProperty("reasoningSummary") ReasoningSummary reasoningSummary, /** Output verbosity level used for model calls, if applicable (e.g. "low", "medium", "high") */ @JsonProperty("verbosity") Verbosity verbosity, /** Context tier currently selected at resume time; null when no tier is active */ @JsonProperty("contextTier") ContextTier contextTier, + /** True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. */ + @JsonProperty("contextTierManaged") Boolean contextTierManaged, /** Auto routing preference active at resume time */ @JsonProperty("autoTier") AutoTier autoTier, + /** True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. */ + @JsonProperty("autoTierManaged") Boolean autoTierManaged, /** Session limits currently configured at resume time; null when no limits are active */ @JsonProperty("sessionLimits") SessionLimitsConfig sessionLimits, /** Updated working directory and git context at resume time */ @@ -68,5 +76,29 @@ public record SessionResumeEventData( /** 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 or omitted, pending work is normally marked as interrupted unless the resume passively joined live work owned by another client; sessionWasActive distinguishes that case. */ @JsonProperty("continuePendingWork") Boolean continuePendingWork ) { + + /** + * Creates event data with the components it had before later optional fields were added. + */ + public SessionResumeEventData( + OffsetDateTime resumeTime, + Long eventCount, + Long eventsFileSizeBytes, + String selectedModel, + String reasoningEffort, + String reasoningEffortModel, + ReasoningSummary reasoningSummary, + Verbosity verbosity, + ContextTier contextTier, + AutoTier autoTier, + SessionLimitsConfig sessionLimits, + WorkingDirectoryContext context, + Boolean alreadyInUse, + Boolean sessionWasActive, + Boolean remoteSteerable, + Boolean continuePendingWork + ) { + this(resumeTime, eventCount, eventsFileSizeBytes, selectedModel, null, reasoningEffort, reasoningEffortModel, null, reasoningSummary, verbosity, contextTier, null, autoTier, null, sessionLimits, context, alreadyInUse, sessionWasActive, remoteSteerable, continuePendingWork); + } } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionShutdownEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionShutdownEvent.java index ab97f6b192..59f09bc9c2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionShutdownEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionShutdownEvent.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import java.util.List; import java.util.Map; import javax.annotation.processing.Generated; @@ -36,6 +37,12 @@ public final class SessionShutdownEvent extends SessionEvent { @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionShutdownEventData( + /** Complete accounting state captured atomically with receipt watermarks. */ + @JsonProperty("accountingSnapshot") UsageGetMetricsResult accountingSnapshot, + /** Provider/model accounting preserved for replay without consulting current provider selection. */ + @JsonProperty("providerModelMetrics") List providerModelMetrics, + /** Per-source accounting sequence watermarks subsuming preceding usage receipts. */ + @JsonProperty("usageAccountingWatermarks") Map usageAccountingWatermarks, /** Whether the session ended normally ("routine") or due to a crash/fatal error ("error") */ @JsonProperty("shutdownType") ShutdownType shutdownType, /** Error description when shutdownType is "error" */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionStartEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionStartEvent.java index db7336ce68..e3ea9d31e6 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionStartEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionStartEvent.java @@ -47,18 +47,26 @@ public record SessionStartEventData( @JsonProperty("startTime") OffsetDateTime startTime, /** Model selected at session creation time, if any */ @JsonProperty("selectedModel") String selectedModel, + /** Provider of selectedModel at creation time, when explicitly selected. */ + @JsonProperty("providerId") String providerId, /** Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max") */ @JsonProperty("reasoningEffort") String reasoningEffort, /** Model that owns effort embedded in an authored model selection. Omitted for independent reasoning-effort overrides and legacy events. */ @JsonProperty("reasoningEffortModel") String reasoningEffortModel, + /** True when the reasoning effort is a managed-policy default bound to reasoningEffortModel. Omitted for agent-authored, user-authored, independent, and legacy effort. */ + @JsonProperty("reasoningEffortManaged") Boolean reasoningEffortManaged, /** Reasoning summary mode used for model calls, if applicable (e.g. "none", "concise", "detailed") */ @JsonProperty("reasoningSummary") ReasoningSummary reasoningSummary, /** Output verbosity level used for model calls, if applicable (e.g. "low", "medium", "high") */ @JsonProperty("verbosity") Verbosity verbosity, /** Context tier selected at session creation time for models with tiered context pricing; null when no tier is selected (e.g., non-tiered model) */ @JsonProperty("contextTier") ContextTier contextTier, + /** True when contextTier is a managed-policy default. Omitted for user-authored and legacy values. */ + @JsonProperty("contextTierManaged") Boolean contextTierManaged, /** Auto routing preference selected at session creation time */ @JsonProperty("autoTier") AutoTier autoTier, + /** True when autoTier is a managed-policy default. Omitted for user-authored and legacy values. */ + @JsonProperty("autoTierManaged") Boolean autoTierManaged, /** Session limits configured at session creation time, if any */ @JsonProperty("sessionLimits") SessionLimitsConfig sessionLimits, /** Working directory and git context at session start */ @@ -72,5 +80,31 @@ public record SessionStartEventData( /** 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. */ @JsonProperty("detachedFromSpawningParentSessionId") String detachedFromSpawningParentSessionId ) { + + /** + * Creates event data with the components it had before later optional fields were added. + */ + public SessionStartEventData( + String sessionId, + Long version, + String producer, + String copilotVersion, + OffsetDateTime startTime, + String selectedModel, + String reasoningEffort, + String reasoningEffortModel, + ReasoningSummary reasoningSummary, + Verbosity verbosity, + ContextTier contextTier, + AutoTier autoTier, + SessionLimitsConfig sessionLimits, + WorkingDirectoryContext context, + GitHubMcpToolConfig gitHubMcpToolConfig, + Boolean alreadyInUse, + Boolean remoteSteerable, + String detachedFromSpawningParentSessionId + ) { + this(sessionId, version, producer, copilotVersion, startTime, selectedModel, null, reasoningEffort, reasoningEffortModel, null, reasoningSummary, verbosity, contextTier, null, autoTier, null, sessionLimits, context, gitHubMcpToolConfig, alreadyInUse, remoteSteerable, detachedFromSpawningParentSessionId); + } } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionUsageCheckpointEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionUsageCheckpointEvent.java index bdbc1add95..e0fd312afc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionUsageCheckpointEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionUsageCheckpointEvent.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; +import java.util.Map; import javax.annotation.processing.Generated; /** @@ -37,6 +38,12 @@ public final class SessionUsageCheckpointEvent extends SessionEvent { public record SessionUsageCheckpointEventData( /** Session-wide accumulated nano-AI units cost at checkpoint time */ @JsonProperty("totalNanoAiu") Double totalNanoAiu, + /** Complete accounting state captured atomically with the receipt watermarks. */ + @JsonProperty("accountingSnapshot") UsageGetMetricsResult accountingSnapshot, + /** Provider/model accounting snapshot that subsumes preceding usage receipts. */ + @JsonProperty("providerModelMetrics") List providerModelMetrics, + /** Highest accounted sequence per source session; no per-call deduplication history is retained. */ + @JsonProperty("usageAccountingWatermarks") Map usageAccountingWatermarks, /** Total number of premium API requests used at checkpoint time */ @JsonProperty("totalPremiumRequests") Double totalPremiumRequests, /** Internal per-model prompt-cache state used to restore expiration tracking on resume */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredEvent.java index a1f218d26e..c40c6dd6e3 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "skill.context_delivered". Exact skill context delivered to the model during a tool phase. This is not a user submission or another skill invocation. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SkillContextDeliveredEvent extends SessionEvent { public void setData(SkillContextDeliveredEventData data) { this.data = data; } /** Data payload for {@link SkillContextDeliveredEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SkillContextDeliveredEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredRefEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredRefEvent.java index b0468b3be0..a6eec3e548 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredRefEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SkillContextDeliveredRefEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "skill.context_delivered_ref". Internal durable receipt that reconstructs exact model-visible skill context from earlier session content. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class SkillContextDeliveredRefEvent extends SessionEvent { public void setData(SkillContextDeliveredRefEventData data) { this.data = data; } /** Data payload for {@link SkillContextDeliveredRefEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SkillContextDeliveredRefEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SkillInvokedRefEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SkillInvokedRefEvent.java index 5dc09939e9..c05ab65c3d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SkillInvokedRefEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SkillInvokedRefEvent.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.List; import javax.annotation.processing.Generated; /** * Session event "skill.invoked_ref". Internal durable skill invocation receipt whose content resolves from an earlier inline skill event in the same session. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -32,6 +36,7 @@ public final class SkillInvokedRefEvent extends SessionEvent { public void setData(SkillInvokedRefEventData data) { this.data = data; } /** Data payload for {@link SkillInvokedRefEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SkillInvokedRefEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UiEphemeralQueryEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/UiEphemeralQueryEvent.java index b2f390e823..2c5620b443 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/UiEphemeralQueryEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UiEphemeralQueryEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "ui.ephemeral_query". Ordered output and terminal state for a transient query that does not modify conversation history. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class UiEphemeralQueryEvent extends SessionEvent { public void setData(UiEphemeralQueryEventData data) { this.data = data; } /** Data payload for {@link UiEphemeralQueryEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record UiEphemeralQueryEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageAccountingIdentity.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageAccountingIdentity.java new file mode 100644 index 0000000000..317aefc28c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageAccountingIdentity.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Ordered accounting identity assigned under the source session's emission lock. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageAccountingIdentity( + /** Session that assigned this accounting sequence. */ + @JsonProperty("sourceSessionId") String sourceSessionId, + /** Monotonically increasing sequence within the source session. */ + @JsonProperty("sequence") Long sequence, + /** Existing API call identifier, or a runtime-generated identity when none was supplied. */ + @JsonProperty("usageId") String usageId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageGetMetricsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageGetMetricsResult.java new file mode 100644 index 0000000000..9142a777e9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageGetMetricsResult.java @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Accumulated session usage metrics, including premium request cost, token counts, model breakdown, and code-change totals. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageGetMetricsResult( + /** Completeness of totalNanoAiu. Numeric totals remain the reported subtotal; zero is not a claim of free usage when unavailable. */ + @JsonProperty("aiCreditsStatus") AiCreditsStatus aiCreditsStatus, + /** Total user-initiated premium request cost across all models (may be fractional due to multipliers) */ + @JsonProperty("totalPremiumRequestCost") Double totalPremiumRequestCost, + /** Raw count of user-initiated API requests */ + @JsonProperty("totalUserRequests") Long totalUserRequests, + /** Session-wide accumulated nano-AI units cost */ + @JsonProperty("totalNanoAiu") Double totalNanoAiu, + /** Session-wide per-token-type accumulated token counts */ + @JsonProperty("tokenDetails") Map tokenDetails, + /** Total time spent in model API calls (milliseconds) */ + @JsonProperty("totalApiDurationMs") Long totalApiDurationMs, + /** ISO 8601 timestamp when the session started */ + @JsonProperty("sessionStartTime") OffsetDateTime sessionStartTime, + /** Aggregated code change metrics */ + @JsonProperty("codeChanges") UsageMetricsCodeChanges codeChanges, + /** Per-model token and request metrics, keyed by model identifier */ + @JsonProperty("modelMetrics") Map modelMetrics, + /** Provider-attributed model metrics, ordered by first observed provider and model. +Null attribution preserves historical usage whose provider or model was not recorded. */ + @JsonProperty("providerModelMetrics") List providerModelMetrics, + /** Per-agent usage metrics, keyed by agent instance identifier. The main conversation uses the stable key `main`. */ + @JsonProperty("agentMetrics") Map agentMetrics, + /** Currently active model identifier */ + @JsonProperty("currentModel") String currentModel, + /** Input tokens from the most recent main-agent API call */ + @JsonProperty("lastCallInputTokens") Long lastCallInputTokens, + /** Output tokens from the most recent main-agent API call */ + @JsonProperty("lastCallOutputTokens") Long lastCallOutputTokens +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsAgentMetric.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsAgentMetric.java new file mode 100644 index 0000000000..a0e9f07d60 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsAgentMetric.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Usage attributed to one agent instance, including its identity, API duration, AI units, and per-model breakdown. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsAgentMetric( + /** Configured agent name, when this is a subagent */ + @JsonProperty("agentName") String agentName, + /** Human-readable label for this subagent invocation, copied from the originating `subagent.started` event. For task-tool subagents this is the invocation's task description rather than the agent's configured display name, so group by `agentName` for stable per-agent labels. */ + @JsonProperty("agentDisplayName") String agentDisplayName, + /** Time spent in model API calls by this agent, in milliseconds */ + @JsonProperty("totalApiDurationMs") Long totalApiDurationMs, + /** Accumulated nano-AI units cost for this agent */ + @JsonProperty("totalNanoAiu") Double totalNanoAiu, + /** Per-model usage for this agent, keyed by model identifier */ + @JsonProperty("modelMetrics") Map modelMetrics +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsCodeChanges.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsCodeChanges.java new file mode 100644 index 0000000000..92f117b26b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsCodeChanges.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Aggregated code change metrics + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsCodeChanges( + /** Total lines of code added */ + @JsonProperty("linesAdded") Long linesAdded, + /** Total lines of code removed */ + @JsonProperty("linesRemoved") Long linesRemoved, + /** Number of distinct files modified */ + @JsonProperty("filesModifiedCount") Long filesModifiedCount, + /** Distinct file paths modified during the session */ + @JsonProperty("filesModified") List filesModified +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetric.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetric.java new file mode 100644 index 0000000000..e55b06e3e9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetric.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.OffsetDateTime; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Per-model usage metrics, including request counts/costs, token usage, nano-AI units, and per-token-type details. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsModelMetric( + /** Completeness of this model's reported AI-credit subtotal. Explicitly reported zero is complete, not unavailable. */ + @JsonProperty("aiCreditsStatus") AiCreditsStatus aiCreditsStatus, + /** Request count and cost metrics for this model */ + @JsonProperty("requests") UsageMetricsModelMetricRequests requests, + /** Token usage metrics for this model */ + @JsonProperty("usage") UsageMetricsModelMetricUsage usage, + /** Latest known prompt-cache expiration for this model. A timestamp in the past indicates that the observed cache has expired. */ + @JsonProperty("cacheExpiresAt") OffsetDateTime cacheExpiresAt, + /** Accumulated nano-AI units cost for this model */ + @JsonProperty("totalNanoAiu") Double totalNanoAiu, + /** Token count details per type */ + @JsonProperty("tokenDetails") Map tokenDetails +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricRequests.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricRequests.java new file mode 100644 index 0000000000..56951bf8ee --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricRequests.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Request count and cost metrics for this model + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsModelMetricRequests( + /** Number of API requests made with this model */ + @JsonProperty("count") Long count, + /** User-initiated premium request cost (with multiplier applied) */ + @JsonProperty("cost") Double cost +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricTokenDetail.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricTokenDetail.java new file mode 100644 index 0000000000..64bdc0c797 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricTokenDetail.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Per-model token-detail entry containing the accumulated token count for one token type. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsModelMetricTokenDetail( + /** Accumulated token count for this token type */ + @JsonProperty("tokenCount") Long tokenCount +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricUsage.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricUsage.java new file mode 100644 index 0000000000..e984a1b823 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsModelMetricUsage.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Token usage metrics for this model + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsModelMetricUsage( + /** Total input tokens consumed */ + @JsonProperty("inputTokens") Long inputTokens, + /** Total output tokens produced */ + @JsonProperty("outputTokens") Long outputTokens, + /** Total tokens read from prompt cache */ + @JsonProperty("cacheReadTokens") Long cacheReadTokens, + /** Total tokens written to prompt cache */ + @JsonProperty("cacheWriteTokens") Long cacheWriteTokens, + /** Total output tokens used for reasoning */ + @JsonProperty("reasoningTokens") Long reasoningTokens +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsProviderModelMetric.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsProviderModelMetric.java new file mode 100644 index 0000000000..27e17e6ba6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsProviderModelMetric.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Usage for one recorded provider and model, without merging identical model IDs across providers. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsProviderModelMetric( + /** Provider identity and product label captured when the call was dispatched; null when unknown. */ + @JsonProperty("provider") ModelProviderRef provider, + /** Model identity, or null for legacy aggregate-only usage. */ + @JsonProperty("modelId") String modelId, + /** Model display name captured at call time, when known. */ + @JsonProperty("modelDisplayName") String modelDisplayName, + /** Request, token, and cost totals for this provider/model. */ + @JsonProperty("metrics") UsageMetricsModelMetric metrics +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsTokenDetail.java b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsTokenDetail.java new file mode 100644 index 0000000000..2e30d0bf90 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/UsageMetricsTokenDetail.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Session-wide token-detail entry containing the accumulated token count for one token type. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsTokenDetail( + /** Accumulated token count for this token type */ + @JsonProperty("tokenCount") Long tokenCount +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunSettledEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunSettledEvent.java index 7cfef0df02..944dacd0df 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunSettledEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunSettledEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "workflow.run_settled". Ephemeral signal that a workflow run reached a terminal status. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class WorkflowRunSettledEvent extends SessionEvent { public void setData(WorkflowRunSettledEventData data) { this.data = data; } /** Data payload for {@link WorkflowRunSettledEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record WorkflowRunSettledEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunStartedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunStartedEvent.java index 656b51f596..fa12ead80a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunStartedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunStartedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "workflow.run_started". Ephemeral signal that a workflow run attempt began executing. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class WorkflowRunStartedEvent extends SessionEvent { public void setData(WorkflowRunStartedEventData data) { this.data = data; } /** Data payload for {@link WorkflowRunStartedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record WorkflowRunStartedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunUpdatedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunUpdatedEvent.java index 6a51db49f6..1a9350e018 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunUpdatedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/WorkflowRunUpdatedEvent.java @@ -10,12 +10,16 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Session event "workflow.run_updated". Ephemeral invalidation signal for a changed workflow run. + * + * @apiNote This event type is experimental and may change in a future version. * @since 1.0.0 */ +@CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) @javax.annotation.processing.Generated("copilot-sdk-codegen") @@ -31,6 +35,7 @@ public final class WorkflowRunUpdatedEvent extends SessionEvent { public void setData(WorkflowRunUpdatedEventData data) { this.data = data; } /** Data payload for {@link WorkflowRunUpdatedEvent}. */ + @CopilotExperimental @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record WorkflowRunUpdatedEventData( diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountAuthInfo.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountAuthInfo.java new file mode 100644 index 0000000000..b6a93fb206 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountAuthInfo.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * An interactive account whose model provider owns its credentials. It carries no GitHub credential. + * + * @since 1.0.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class AccountAuthInfo extends AuthInfo { + + @JsonProperty("type") + private final String type = "account"; + + @Override + public String getType() { return type; } + + /** Host coordinate owned by the account's model provider. */ + @JsonProperty("host") + private String host; + + /** Login identifying the provider-owned account. */ + @JsonProperty("login") + private String login; + + public String getHost() { return host; } + public void setHost(String host) { this.host = host; } + + public String getLogin() { return login; } + public void setLogin(String login) { this.login = login; } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoParams.java new file mode 100644 index 0000000000..83a49d849a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The authentication identity whose shared wording should be rendered. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountDescribeAuthInfoParams( + /** Identity to describe. */ + @JsonProperty("identity") AuthIdentity identity +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoResult.java new file mode 100644 index 0000000000..8fcc083bbb --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The wording the runtime uses for an authentication identity. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountDescribeAuthInfoResult( + /** Sign-in banner announcing the authenticated user. */ + @JsonProperty("message") String message, + /** One-line description of the identity, suitable after a verb such as "Switched to". */ + @JsonProperty("description") String description +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportParams.java new file mode 100644 index 0000000000..76c1a53037 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The authentication identity whose gist support should be reported. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetGistSupportParams( + /** Identity to evaluate. */ + @JsonProperty("identity") AuthIdentity identity +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportResult.java new file mode 100644 index 0000000000..03862487a0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Whether the identity can create gists, and why not when it cannot. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetGistSupportResult( + /** True when the identity can create gists. */ + @JsonProperty("supported") Boolean supported, + /** Machine-readable reason category when unsupported. */ + @JsonProperty("kind") String kind, + /** Human-readable explanation to show where the gist action would have been. */ + @JsonProperty("reason") String reason +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetTokenEnvVarResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetTokenEnvVarResult.java new file mode 100644 index 0000000000..5e7c2aacf5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetTokenEnvVarResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The environment variable supplying a classic personal access token, when one is set. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetTokenEnvVarResult( + /** Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. */ + @JsonProperty("name") String name +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlParams.java new file mode 100644 index 0000000000..7b4c7686c4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A path to resolve against the GitHub host an identity is signed in to. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetWebUrlParams( + /** Host-relative path, without a leading slash, for example `settings/copilot/features`. */ + @JsonProperty("path") String path, + /** Identity whose host the path resolves against. Omit to resolve against the public github.com host. */ + @JsonProperty("identity") AuthIdentity identity +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlResult.java new file mode 100644 index 0000000000..5aa680cacd --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * An absolute URL on the identity's GitHub host. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetWebUrlResult( + /** Absolute URL for the requested path. */ + @JsonProperty("url") String url +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java index cb0868ce74..7cdebb3d29 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java @@ -31,6 +31,8 @@ public record AccountStatus( @JsonProperty("login") String login, /** The provider kind of this account. */ @JsonProperty("kind") AccountKind kind, + /** Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. */ + @JsonProperty("authSource") String authSource, /** Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. */ @JsonProperty("derivedFrom") String derivedFrom, /** Whether this is the active account. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java index 27fd56a428..17debc1a4c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java @@ -54,6 +54,8 @@ public record AgentInfo( /** Skill names preloaded into this agent's context. Omitted means none. */ @JsonProperty("skills") List skills, /** Authored base prompt for the agent. Runtime prompt assembly may add dynamic context at invocation time. Omitted from `session.agent.list` unless `includePrompt` is true. */ - @JsonProperty("prompt") String prompt + @JsonProperty("prompt") String prompt, + /** Declarative hook actions keyed by event name, executed only while this agent is active. */ + @JsonProperty("hooks") Map> hooks ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsCustomAgentInitialModelDecisionParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsCustomAgentInitialModelDecisionParams.java new file mode 100644 index 0000000000..1555b36663 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsCustomAgentInitialModelDecisionParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The models a custom agent asks for, and the models actually available. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsCustomAgentInitialModelDecisionParams( + /** The agent's declared `model:` entry, serialized. A single name or an ordered list of acceptable names. */ + @JsonProperty("agentModelsJson") String agentModelsJson, + /** The models available to this session, serialized in the shape the model list carries. */ + @JsonProperty("availableModelsJson") String availableModelsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsCustomAgentInitialModelDecisionResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsCustomAgentInitialModelDecisionResult.java new file mode 100644 index 0000000000..afd26e66af --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsCustomAgentInitialModelDecisionResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The model to switch to, and the warning to show when the agent's preference could not be met. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsCustomAgentInitialModelDecisionResult( + /** The first available model that matches the agent's preferences. Absent when none of the requested models is available. */ + @JsonProperty("targetModel") String targetModel, + /** The reasoning effort attached to the selected model preference. Absent when that preference does not specify an effort. */ + @JsonProperty("reasoningEffort") String reasoningEffort, + /** What to tell the user about an unmet preference. Absent when the preference was met. A warning with no `targetModel` means the agent's models are all unavailable. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsDiscoverRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsDiscoverRequest.java new file mode 100644 index 0000000000..26ead3977a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsDiscoverRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include in agent discovery. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class AgentsDiscoverRequest { + + /** Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. */ + @JsonProperty("excludeHostAgents") + private Boolean excludeHostAgents; + + /** Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ + @JsonProperty("agentDirectories") + private List agentDirectories; + + /** + * Creates a request with its required inputs. + */ + public AgentsDiscoverRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostAgents} property. + * + * @return When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. + */ + public Boolean getExcludeHostAgents() { + return excludeHostAgents; + } + + /** + * Returns the {@code agentDirectories} property. + * + * @return Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + public List getAgentDirectories() { + return agentDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). + * @return this request + */ + public AgentsDiscoverRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostAgents} property. + * + * @param value When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. + * @return this request + */ + public AgentsDiscoverRequest setExcludeHostAgents(Boolean value) { + this.excludeHostAgents = value; + return this; + } + + /** + * Sets the {@code agentDirectories} property. + * + * @param value Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + * @return this request + */ + public AgentsDiscoverRequest setAgentDirectories(List value) { + this.agentDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetAvailableBuiltinsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetAvailableBuiltinsParams.java new file mode 100644 index 0000000000..fee8d13df9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetAvailableBuiltinsParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The feature flags to evaluate shipped agents against. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsGetAvailableBuiltinsParams( + /** Feature flag values keyed by name, evaluated with the runtime's truthiness rules. Omit or pass null for no flags. */ + @JsonProperty("featureFlags") Map featureFlags, + /** Flag overrides keyed by name. A null entry uses the corresponding base flag; false explicitly disables it. Omit or pass null for no overrides. */ + @JsonProperty("overrides") Map overrides, + /** The surface asking, which gates agents that only apply to one client. Omit or pass null to apply no client filter. */ + @JsonProperty("context") String context +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetAvailableBuiltinsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetAvailableBuiltinsResult.java new file mode 100644 index 0000000000..14667e1269 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetAvailableBuiltinsResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The shipped agents available under the requested flags. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsGetAvailableBuiltinsResult( + /** Available shipped agents, in the runtime's own order. */ + @JsonProperty("agents") List agents +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinDefinitionParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinDefinitionParams.java new file mode 100644 index 0000000000..cc69529078 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinDefinitionParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The shipped agent whose definition to load. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsGetBuiltinDefinitionParams( + /** The agent name, which must be one of `getBuiltins`'s `yamlBasedNames`. A name outside that list is special-cased in code and has no definition, and is reported as an error rather than as an empty definition. */ + @JsonProperty("name") String name +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinDefinitionResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinDefinitionResult.java new file mode 100644 index 0000000000..2fd4d55fa3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinDefinitionResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One shipped agent's definition. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsGetBuiltinDefinitionResult( + /** The agent's definition, serialized as JSON. It carries the authored keys plus the runtime's projected `__nativeCustomAgent` view of the same agent. It is a string rather than an object because the runtime parses it with the agent schema's tolerant shape, which accepts keys this contract does not name. */ + @JsonProperty("definitionJson") String definitionJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinListingDefinitionParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinListingDefinitionParams.java new file mode 100644 index 0000000000..9258f87d1b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinListingDefinitionParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The shipped agent whose listing entry to load. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsGetBuiltinListingDefinitionParams( + /** The agent name, taken from `getAvailableBuiltins`. Unlike `getBuiltinDefinition`, the agent that `getBuiltins` reports as special-cased rather than YAML-based is answered here too, from its in-code definition. */ + @JsonProperty("name") String name +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinListingDefinitionResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinListingDefinitionResult.java new file mode 100644 index 0000000000..f49d37d53b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinListingDefinitionResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One shipped agent, projected for a listing. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsGetBuiltinListingDefinitionResult( + /** The agent projected as a custom agent, serialized as JSON. It is a string rather than an object for the same reason as `getBuiltinDefinition`: the runtime parses the underlying definition with the agent schema's tolerant shape, which accepts keys this contract does not name. */ + @JsonProperty("definitionJson") String definitionJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinsResult.java new file mode 100644 index 0000000000..d0148ac6d7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetBuiltinsResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The agents this runtime ships, named so a consumer can tell them apart from authored ones. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AgentsGetBuiltinsResult( + /** Every agent name this runtime ships. */ + @JsonProperty("names") List names, + /** The subset of `names` a user is allowed to turn off. A shipped agent outside this list is always active and a client should not offer a toggle for it. */ + @JsonProperty("disableableNames") List disableableNames, + /** The subset of `names` defined by a shipped YAML definition. The remainder are special-cased in code and have no definition to load. */ + @JsonProperty("yamlBasedNames") List yamlBasedNames +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetDiscoveryPathsRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetDiscoveryPathsRequest.java new file mode 100644 index 0000000000..fe9123f9ba --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetDiscoveryPathsRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include when enumerating agent discovery directories. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class AgentsGetDiscoveryPathsRequest { + + /** Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). */ + @JsonProperty("excludeHostAgents") + private Boolean excludeHostAgents; + + /** Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. */ + @JsonProperty("agentDirectories") + private List agentDirectories; + + /** + * Creates a request with its required inputs. + */ + public AgentsGetDiscoveryPathsRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostAgents} property. + * + * @return When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). + */ + public Boolean getExcludeHostAgents() { + return excludeHostAgents; + } + + /** + * Returns the {@code agentDirectories} property. + * + * @return Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + public List getAgentDirectories() { + return agentDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. + * @return this request + */ + public AgentsGetDiscoveryPathsRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostAgents} property. + * + * @param value When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). + * @return this request + */ + public AgentsGetDiscoveryPathsRequest setExcludeHostAgents(Boolean value) { + this.excludeHostAgents = value; + return this; + } + + /** + * Sets the {@code agentDirectories} property. + * + * @param value Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + * @return this request + */ + public AgentsGetDiscoveryPathsRequest setAgentDirectories(List value) { + this.agentDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AiCreditsStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AiCreditsStatus.java new file mode 100644 index 0000000000..cc13ac67a4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AiCreditsStatus.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Whether the accumulated numeric AI-credit subtotal covers the observed calls. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum AiCreditsStatus { + /** The {@code complete} variant. */ + COMPLETE("complete"), + /** The {@code partial} variant. */ + PARTIAL("partial"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"); + + private final String value; + AiCreditsStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static AiCreditsStatus fromValue(String value) { + for (AiCreditsStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown AiCreditsStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthIdentity.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthIdentity.java index dfeb3c023a..7768741926 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthIdentity.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthIdentity.java @@ -20,7 +20,7 @@ @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -record AuthIdentity( +public record AuthIdentity( /** Authentication type */ @JsonProperty("type") AuthInfoType type, /** Authentication host */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfo.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfo.java index 5d82a47f85..7b03a6a29a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfo.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfo.java @@ -25,6 +25,7 @@ @JsonSubTypes.Type(value = TokenProviderAuthInfo.class, name = "token-provider"), @JsonSubTypes.Type(value = CopilotApiTokenAuthInfo.class, name = "copilot-api-token"), @JsonSubTypes.Type(value = UserAuthInfo.class, name = "user"), + @JsonSubTypes.Type(value = AccountAuthInfo.class, name = "account"), @JsonSubTypes.Type(value = GhCliAuthInfo.class, name = "gh-cli"), @JsonSubTypes.Type(value = ApiKeyAuthInfo.class, name = "api-key") }) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfoType.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfoType.java index 5f81c8cf84..1be60446c1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfoType.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthInfoType.java @@ -22,6 +22,8 @@ public enum AuthInfoType { ENV("env"), /** The {@code user} variant. */ USER("user"), + /** The {@code account} variant. */ + ACCOUNT("account"), /** The {@code gh-cli} variant. */ GH_CLI("gh-cli"), /** The {@code api-key} variant. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginAccount.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginAccount.java new file mode 100644 index 0000000000..87405999ed --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginAccount.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A credential-free account choice after sign-in. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record AuthLoginAccount( + /** Opaque identifier supplied to the next login step to select this account. */ + @JsonProperty("selectionId") String selectionId, + /** Host coordinate owned by the selected account's provider. */ + @JsonProperty("host") String host, + /** Human-readable login for the account choice. */ + @JsonProperty("login") String login, + /** Provider kind that owns this account choice. */ + @JsonProperty("kind") AccountKind kind +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultDto.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultDto.java index cbcffb6e54..ecbb106f12 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultDto.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultDto.java @@ -11,10 +11,11 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import java.util.List; import javax.annotation.processing.Generated; /** - * Terminal result of an interactive login flow. + * Result of an interactive login flow. Pending consent or account selection is not terminal. * * @apiNote This type is experimental and may change in a future version. * @@ -25,11 +26,13 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record AuthLoginResultDto( - /** Terminal disposition of the login. */ + /** Current disposition of the login, including pending user decisions. */ @JsonProperty("status") AuthLoginResultStatus status, /** Host that was signed in, when completed. */ @JsonProperty("host") String host, /** Login that was signed in, when completed. */ - @JsonProperty("login") String login + @JsonProperty("login") String login, + /** Available accounts when sign-in is awaiting account selection, ordered with Microsoft 365 first. */ + @JsonProperty("accounts") List accounts ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultStatus.java index 9e36ad0027..07becf2fb9 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultStatus.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginResultStatus.java @@ -11,7 +11,7 @@ import javax.annotation.processing.Generated; /** - * Terminal disposition of a login persistence attempt. + * Disposition of a login attempt, including pending user decisions. * * @apiNote This type is experimental and may change in a future version. * @@ -24,6 +24,8 @@ public enum AuthLoginResultStatus { COMPLETED("completed"), /** The {@code needs-plaintext-consent} variant. */ NEEDS_PLAINTEXT_CONSENT("needs-plaintext-consent"), + /** The {@code needs-account-selection} variant. */ + NEEDS_ACCOUNT_SELECTION("needs-account-selection"), /** The {@code declined} variant. */ DECLINED("declined"); diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginStepCompleted.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginStepCompleted.java index b1fb524643..a8ea53e123 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginStepCompleted.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthLoginStepCompleted.java @@ -32,7 +32,7 @@ public final class AuthLoginStepCompleted extends AuthLoginStep { @Override public String getKind() { return kind; } - /** The terminal login result. */ + /** Login result. When status is needs-plaintext-consent or needs-account-selection, advance with the user's decision to continue. */ @JsonProperty("result") private AuthLoginResultDto result; diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthReadValueActiveAccount.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthReadValueActiveAccount.java index 8ee2fb9416..e10579d0e6 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthReadValueActiveAccount.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AuthReadValueActiveAccount.java @@ -36,6 +36,13 @@ public final class AuthReadValueActiveAccount extends AuthReadValue { @JsonProperty("account") private AccountStatus account; + /** Credential-free identity metadata for the active account, including resolved Copilot user information when available. */ + @JsonProperty("authInfo") + private AuthIdentity authInfo; + public AccountStatus getAccount() { return account; } public void setAccount(AccountStatus account) { this.account = account; } + + public AuthIdentity getAuthInfo() { return authInfo; } + public void setAuthInfo(AuthIdentity authInfo) { this.authInfo = authInfo; } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTier.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTier.java index 00b18bcc94..cc568096a9 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTier.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTier.java @@ -10,30 +10,38 @@ import javax.annotation.processing.Generated; /** - * Routing preference used when the session model is `auto`. `fast` is an integrator-only latency preset and is not a first-party GitHub Copilot product preference. + * Extensible routing preference for the virtual `auto` model. New identifiers must be advertised and enabled by the provider. `fast` is an integrator-only latency preset. * * @since 1.0.0 */ @javax.annotation.processing.Generated("copilot-sdk-codegen") -public enum AutoTier { +public final class AutoTier { /** The {@code efficiency} variant. */ - EFFICIENCY("efficiency"), + public static final AutoTier EFFICIENCY = new AutoTier("efficiency"); /** The {@code balance} variant. */ - BALANCE("balance"), + public static final AutoTier BALANCE = new AutoTier("balance"); /** The {@code intelligence} variant. */ - INTELLIGENCE("intelligence"), + public static final AutoTier INTELLIGENCE = new AutoTier("intelligence"); /** The {@code fast} variant. */ - FAST("fast"); + public static final AutoTier FAST = new AutoTier("fast"); private final String value; - AutoTier(String value) { this.value = value; } + private AutoTier(String value) { this.value = value; } @com.fasterxml.jackson.annotation.JsonValue public String getValue() { return value; } @com.fasterxml.jackson.annotation.JsonCreator public static AutoTier fromValue(String value) { + if (value == null) return null; + if (value.isEmpty() || value.codePoints().anyMatch(c -> Character.isWhitespace(c) || Character.isISOControl(c))) + throw new IllegalArgumentException("AutoTier requires a routing identifier"); for (AutoTier v : values()) { if (v.value.equals(value)) return v; } - throw new IllegalArgumentException("Unknown AutoTier value: " + value); + return new AutoTier(value); } + /** Returns the known routing preferences. @return known values */ + public static AutoTier[] values() { return new AutoTier[] { EFFICIENCY, BALANCE, INTELLIGENCE, FAST }; } + @Override public boolean equals(Object other) { return other instanceof AutoTier v && value.equals(v.value); } + @Override public int hashCode() { return value.hashCode(); } + @Override public String toString() { return value; } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierDescriptor.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierDescriptor.java new file mode 100644 index 0000000000..49616a82a6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierDescriptor.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * A server-advertised routing preference. Identifiers and execution types are extensible. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record AutoTierDescriptor( + /** Opaque routing identifier transmitted unchanged to the provider. */ + @JsonProperty("id") String id, + /** Human-readable label, not a routing identifier. */ + @JsonProperty("displayName") String displayName, + /** Description displayed beside the preference. */ + @JsonProperty("description") String description, + /** Execution kind; this client supports `auto` preferences on the Auto model. */ + @JsonProperty("type") String type, + /** Current account-specific availability. */ + @JsonProperty("status") AutoTierStatus status +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierMetadata.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierMetadata.java new file mode 100644 index 0000000000..347bf55666 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierMetadata.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Account-bound discovery metadata for the virtual `auto` model. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record AutoTierMetadata( + /** Provider-default preference, used only when no explicit preference exists. */ + @JsonProperty("defaultTier") String defaultTier, + /** Routing preferences in the server's presentation order. */ + @JsonProperty("tiers") List tiers, + /** Provider that supplied this metadata, when the catalog is provider-attributed. */ + @JsonProperty("providerId") String providerId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierStatus.java new file mode 100644 index 0000000000..8bf78312b6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AutoTierStatus.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Availability of a server-advertised routing preference. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record AutoTierStatus( + /** Whether the provider permits selecting this preference. */ + @JsonProperty("enabled") Boolean enabled, + /** Extensible machine-readable unavailability reason. */ + @JsonProperty("reason") String reason, + /** Human-readable explanation of availability. */ + @JsonProperty("message") String message +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/BuiltinAgentSummary.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/BuiltinAgentSummary.java new file mode 100644 index 0000000000..65e75ff6f7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/BuiltinAgentSummary.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * A shipped agent, named and described. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record BuiltinAgentSummary( + /** The agent name, as it appears in `getBuiltins`. */ + @JsonProperty("name") String name, + /** One-line description of what the agent does. */ + @JsonProperty("description") String description +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAccount.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAccount.java new file mode 100644 index 0000000000..f41fd3dd79 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAccount.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Eligible account. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorDiscoveryAccount( + /** Opaque account ID. */ + @JsonProperty("accountId") String accountId, + /** Account metadata. */ + @JsonProperty("authInfo") ConnectorDiscoveryAuthInfo authInfo +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAuthInfo.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAuthInfo.java new file mode 100644 index 0000000000..3857e88ff1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAuthInfo.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Account metadata. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorDiscoveryAuthInfo( + /** Authentication type. */ + @JsonProperty("type") AuthInfoType type, + /** Host. */ + @JsonProperty("host") String host, + /** Login. */ + @JsonProperty("login") String login +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAvailability.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAvailability.java new file mode 100644 index 0000000000..00162fc078 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryAvailability.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Availability. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ConnectorDiscoveryAvailability { + /** The {@code enabled} variant. */ + ENABLED("enabled"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"); + + private final String value; + ConnectorDiscoveryAvailability(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ConnectorDiscoveryAvailability fromValue(String value) { + for (ConnectorDiscoveryAvailability v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ConnectorDiscoveryAvailability value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryCatalogEntry.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryCatalogEntry.java new file mode 100644 index 0000000000..76c137c5e2 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorDiscoveryCatalogEntry.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Entry. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorDiscoveryCatalogEntry( + /** Name. */ + @JsonProperty("name") String name, + /** Display name. */ + @JsonProperty("displayName") String displayName, + /** Description. */ + @JsonProperty("description") String description, + /** Logo. */ + @JsonProperty("logo") String logo, + /** Tier. */ + @JsonProperty("tier") String tier, + /** Release tag. */ + @JsonProperty("releaseTag") String releaseTag, + /** Status. */ + @JsonProperty("status") ConnectorCatalogStatus status +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsGetAccountsResult.java similarity index 72% rename from java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetResult.java rename to java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsGetAccountsResult.java index c5ab98621a..1334b673fa 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsGetAccountsResult.java @@ -15,7 +15,7 @@ import javax.annotation.processing.Generated; /** - * Outcome of writing user settings. + * Eligible accounts. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -24,8 +24,10 @@ @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public record UserSettingsSetResult( - /** Top-level keys whose write landed in settings.json but is shadowed by a value still present in the legacy config.json (config.json wins on read). The write does not take effect until the legacy value is removed. */ - @JsonProperty("shadowedKeys") List shadowedKeys +public record ConnectorsGetAccountsResult( + /** Availability. */ + @JsonProperty("availability") ConnectorDiscoveryAvailability availability, + /** Eligible accounts. */ + @JsonProperty("accounts") List accounts ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsGetCapabilitiesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsGetCapabilitiesResult.java new file mode 100644 index 0000000000..dc1b256e27 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsGetCapabilitiesResult.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Feature availability. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorsGetCapabilitiesResult( + /** API version. */ + @JsonProperty("apiVersion") Long apiVersion, + /** Availability. */ + @JsonProperty("availability") ConnectorDiscoveryAvailability availability, + /** Whether accounts are selected by opaque ID. */ + @JsonProperty("opaqueAccountSelection") Boolean opaqueAccountSelection, + /** Whether results are cached. */ + @JsonProperty("conditionalCache") Boolean conditionalCache +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsListParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsListParams.java new file mode 100644 index 0000000000..39a2c4a966 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsListParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selected account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorsListParams( + /** Opaque account ID. */ + @JsonProperty("accountId") String accountId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsListResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsListResult.java new file mode 100644 index 0000000000..ccba6073d4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsListResult.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Entries for the selected account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorsListResult( + /** Opaque account ID. */ + @JsonProperty("accountId") String accountId, + /** Revision. */ + @JsonProperty("revision") Long revision, + /** Refresh time in Unix epoch milliseconds. */ + @JsonProperty("refreshedAtMs") Long refreshedAtMs, + /** Entries. */ + @JsonProperty("connectors") List connectors +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsRefreshParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsRefreshParams.java new file mode 100644 index 0000000000..e5384ba3f2 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsRefreshParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selected account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorsRefreshParams( + /** Opaque account ID. */ + @JsonProperty("accountId") String accountId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsRefreshResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsRefreshResult.java new file mode 100644 index 0000000000..a14c50fd28 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ConnectorsRefreshResult.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Entries for the selected account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ConnectorsRefreshResult( + /** Opaque account ID. */ + @JsonProperty("accountId") String accountId, + /** Revision. */ + @JsonProperty("revision") Long revision, + /** Refresh time in Unix epoch milliseconds. */ + @JsonProperty("refreshedAtMs") Long refreshedAtMs, + /** Entries. */ + @JsonProperty("connectors") List connectors +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/CurrentModel.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/CurrentModel.java index 3088672b69..6fa6843944 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/CurrentModel.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/CurrentModel.java @@ -23,8 +23,12 @@ public record CurrentModel( /** Currently active model identifier */ @JsonProperty("modelId") String modelId, + /** Provider selected for this model. Together with modelId, identifies a catalog entry even when providers serve the same model. Omitted for unattributed legacy selections. */ + @JsonProperty("providerId") String providerId, /** Captured base model to restore when leaving plan mode. Omitted outside plan mode or when no plan override has captured a base model. Persistent agent model requirements apply to this model rather than the temporary plan model. */ @JsonProperty("planBaseModelId") String planBaseModelId, + /** Provider of planBaseModelId, when that saved selection is provider-qualified. */ + @JsonProperty("planBaseProviderId") String planBaseProviderId, /** Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. */ @JsonProperty("reasoningEffort") String reasoningEffort, /** Context tier for models that support multiple context-window sizes. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentCapabilities.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentCapabilities.java index f261c345db..3bbe3e31a0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentCapabilities.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentCapabilities.java @@ -10,14 +10,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.List; import javax.annotation.processing.Generated; /** * Hosting capabilities and session capacity advertised by an environment. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentKind.java index d7ae216cce..f3d45cafc1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentKind.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/EnvironmentKind.java @@ -7,13 +7,17 @@ package com.github.copilot.generated.rpc; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * GitHub Mission Control compute kind. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") public enum EnvironmentKind { /** The {@code user-local} variant. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagAvailability.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagAvailability.java new file mode 100644 index 0000000000..953a52226c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagAvailability.java @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * The population a feature flag is declared for, before overrides. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum FeatureFlagAvailability { + /** The {@code on} variant. */ + ON("on"), + /** The {@code team} variant. */ + TEAM("team"), + /** The {@code staff-and-experimental} variant. */ + STAFF_AND_EXPERIMENTAL("staff-and-experimental"), + /** The {@code staff-or-experimental} variant. */ + STAFF_OR_EXPERIMENTAL("staff-or-experimental"), + /** The {@code staff} variant. */ + STAFF("staff"), + /** The {@code staff-github} variant. */ + STAFF_GITHUB("staff-github"), + /** The {@code staff-microsoft} variant. */ + STAFF_MICROSOFT("staff-microsoft"), + /** The {@code experimental} variant. */ + EXPERIMENTAL("experimental"), + /** The {@code off} variant. */ + OFF("off"); + + private final String value; + FeatureFlagAvailability(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static FeatureFlagAvailability fromValue(String value) { + for (FeatureFlagAvailability v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown FeatureFlagAvailability value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagMetadata.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagMetadata.java new file mode 100644 index 0000000000..49ac33f82f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagMetadata.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The declared shape of one feature flag, independent of any caller population. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagMetadata( + /** The flag's name, matching the key it is listed under. */ + @JsonProperty("name") String name, + /** The population the flag is declared for before any environment or user-settings override is applied. */ + @JsonProperty("availability") FeatureFlagAvailability availability, + /** Whether the flag participates in the CAPI sanity suite. */ + @JsonProperty("capiSanity") Boolean capiSanity, + /** Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. */ + @JsonProperty("experimentalDescription") String experimentalDescription, + /** The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. */ + @JsonProperty("expFlag") String expFlag, + /** Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. */ + @JsonProperty("expFlagEnvVar") String expFlagEnvVar +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsMetadataResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsMetadataResult.java new file mode 100644 index 0000000000..01e738c670 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsMetadataResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Every feature flag this runtime declares, with the shape each one was declared with. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagsMetadataResult( + /** Declared feature flags keyed by flag name. */ + @JsonProperty("flags") Map flags +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveParams.java new file mode 100644 index 0000000000..bf459ff033 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveParams.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagsResolveParams( + /** Whether the caller is GitHub or Microsoft staff. */ + @JsonProperty("isStaff") Boolean isStaff, + /** Whether the caller is in an experimental population. */ + @JsonProperty("isExperimental") Boolean isExperimental, + /** Whether the caller belongs to the team population used by feature availability. */ + @JsonProperty("isTeam") Boolean isTeam, + /** GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. */ + @JsonProperty("isStaffGithub") Boolean isStaffGitHub, + /** Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. */ + @JsonProperty("isStaffMicrosoft") Boolean isStaffMicrosoft, + /** Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. */ + @JsonProperty("baseFlags") Map baseFlags, + /** Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. */ + @JsonProperty("environment") Map environment, + /** User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. */ + @JsonProperty("config") Object config, + /** Flags forced to a value after every other layer, keyed by flag name. */ + @JsonProperty("flagOverrides") Map flagOverrides +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveStartupGatesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveStartupGatesParams.java new file mode 100644 index 0000000000..3a08c2e5b8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveStartupGatesParams.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagsResolveStartupGatesParams( + /** The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. */ + @JsonProperty("flags") List flags, + /** Whether the caller is GitHub or Microsoft staff. */ + @JsonProperty("isStaff") Boolean isStaff, + /** Whether the caller is in an experimental population. */ + @JsonProperty("isExperimental") Boolean isExperimental, + /** Whether the caller belongs to a team plan. */ + @JsonProperty("isTeam") Boolean isTeam, + /** GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. */ + @JsonProperty("isStaffGithub") Boolean isStaffGitHub, + /** Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. */ + @JsonProperty("isStaffMicrosoft") Boolean isStaffMicrosoft, + /** Environment to read flag overrides from. Defaults to this runtime process's own environment. */ + @JsonProperty("environment") Map environment, + /** User settings document whose `featureFlags` block is layered on top of the resolved set. */ + @JsonProperty("config") Object config, + /** Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. */ + @JsonProperty("streamerMode") Boolean streamerMode, + /** When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. */ + @JsonProperty("firstLaunchAtMillis") Double firstLaunchAtMillis, + /** Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. */ + @JsonProperty("refreshWithoutSession") Boolean refreshWithoutSession +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FolderTrustCheckResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FolderTrustCheckResult.java new file mode 100644 index 0000000000..746ad554f5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FolderTrustCheckResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Folder trust check result. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record FolderTrustCheckResult( + /** Whether the folder is trusted */ + @JsonProperty("trusted") Boolean trusted +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ForceLoginOrgsDecision.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ForceLoginOrgsDecision.java new file mode 100644 index 0000000000..24218c69e5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ForceLoginOrgsDecision.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ForceLoginOrgsDecision( + /** Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is never blocked. */ + @JsonProperty("allowed") Boolean allowed, + /** Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed because the account is approved", which a diagnostics surface needs and which also decides whether a bring-your-own-key provider may serve inference. */ + @JsonProperty("enforced") Boolean enforced, + /** The approved organization logins, as configured. Enterprise configuration rather than user data, so it is safe to name in a message or a log line. */ + @JsonProperty("requiredOrgs") List requiredOrgs, + /** The approved organization the account matched, when allowed under a pin. */ + @JsonProperty("matchedOrg") String matchedOrg, + /** A stable kebab-case reason code when refused: `org-not-approved`, `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal rather than mapping it to an allow: a code this host has not been taught about still denied the credential. */ + @JsonProperty("denial") String denial, + /** A developer-facing explanation of the refusal. Omitted when allowed. */ + @JsonProperty("message") String message, + /** Error-level detail from managed-policy discovery — which file failed to load, which field failed validation. Carried on the decision rather than left to the log because a refusal can exit the process before a log sink exists, which would discard the only actionable diagnostic a misconfigured managed device produces. */ + @JsonProperty("policyDiagnostics") List policyDiagnostics +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitCurrentBranchRemoteParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitCurrentBranchRemoteParams.java new file mode 100644 index 0000000000..67f7b64880 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitCurrentBranchRemoteParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Working-tree path a git query applies to. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitCurrentBranchRemoteParams( + /** Absolute path to a directory inside the git working tree to query. */ + @JsonProperty("cwd") String cwd +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitCurrentBranchRemoteResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitCurrentBranchRemoteResult.java new file mode 100644 index 0000000000..faa7e52b3d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitCurrentBranchRemoteResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The remote the checked-out branch tracks. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitCurrentBranchRemoteResult( + /** Name of the tracked remote. Reports `origin` whenever the working tree has no tracking configuration to read, including on a detached HEAD, so this is never null and never empty. */ + @JsonProperty("remote") String remote +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubEnvironment.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubEnvironment.java index fffed71974..c17b2c9778 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubEnvironment.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubEnvironment.java @@ -10,14 +10,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.Map; import javax.annotation.processing.Generated; /** * Safe discovery information. Host-side relay bootstrap credentials are never included. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnerOption.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnerOption.java new file mode 100644 index 0000000000..43e3d2d01d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnerOption.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * A GitHub login the authenticated user may act as: their own account, or an organization they belong to. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubOwnerOption( + /** The owner's GitHub login. */ + @JsonProperty("login") String login, + /** Which kind of owner this is. The authenticated user's own account is always reported as `user`. */ + @JsonProperty("type") String type +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersCancelParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersCancelParams.java new file mode 100644 index 0000000000..1ea9251095 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersCancelParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The owner listing to abandon. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubOwnersCancelParams( + /** Request id the listing was started with. */ + @JsonProperty("requestId") Long requestId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersCancelResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersCancelResult.java new file mode 100644 index 0000000000..d70a718261 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersCancelResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Whether the id named a running owner listing. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubOwnersCancelResult( + /** True when a listing with the id was running and the cancel stopped it. False when the id was never registered, was registered but unused, was released after being abandoned, or its listing had ended. An unused id is released and cannot start a later listing. */ + @JsonProperty("canceled") Boolean canceled +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListParams.java new file mode 100644 index 0000000000..fd1489b805 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Credential to list owners under, and the request id that makes the listing cancellable. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubOwnersListParams( + /** Request id from `gitHubOwners.nextRequestId`. An id that was never registered, canceled before use, released after being abandoned, or already used is refused rather than silently running uncancellable. */ + @JsonProperty("requestId") Long requestId, + /** The credential the listing runs under, carried opaquely because its shape is the host's own and the runtime only resolves a token and a GitHub host from it. No credential travels: this selects one the runtime already holds. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("authInfo") Object authInfo +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListResult.java new file mode 100644 index 0000000000..02f844bced --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListResult.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Outcome of an owner listing. Exactly one of `owners` and `message` is present, except that `throwError` reports a failure the caller is expected to raise rather than render. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubOwnersListResult( + /** The owners, on success: the authenticated user first, then the organizations they belong to. */ + @JsonProperty("owners") List owners, + /** Why no owners could be listed, phrased for a user. Present when the listing failed in a way the caller should render rather than raise. */ + @JsonProperty("message") String message, + /** A line the caller should log. Present only alongside `message`, and only for failures worth recording. */ + @JsonProperty("warning") String warning, + /** A malformed request or an unreadable credential, which the caller raises instead of rendering. Kept a field rather than a dispatch error so it stays distinct from `message`, which the caller renders. */ + @JsonProperty("throwError") String throwError +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersRequestIdResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersRequestIdResult.java new file mode 100644 index 0000000000..8b5d180b05 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersRequestIdResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubOwnersRequestIdResult( + /** Request id to pass to `gitHubOwners.list` and, to abandon it, `gitHubOwners.cancel`. */ + @JsonProperty("requestId") Long requestId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryAtPathParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryAtPathParams.java new file mode 100644 index 0000000000..6a896bff33 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryAtPathParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Working-tree path whose owning GitHub repository should be resolved. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubRepositoryAtPathParams( + /** Absolute path to a directory inside the git working tree to resolve. */ + @JsonProperty("path") String path +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryAtPathResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryAtPathResult.java new file mode 100644 index 0000000000..f32a3eafc0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryAtPathResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The GitHub repository that owns the requested path, when the selected remote (`origin`, else the first) is on a GitHub host. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubRepositoryAtPathResult( + /** Resolved repository identity, or null when the selected remote resolves to no GitHub host. */ + @JsonProperty("repository") GitHubRepositoryIdentity repository +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryIdentity.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryIdentity.java new file mode 100644 index 0000000000..a1d8c3acc3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubRepositoryIdentity.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Owner, name, and host of a GitHub repository, as resolved from a git remote URL. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitHubRepositoryIdentity( + /** Repository owner login (user or organization). */ + @JsonProperty("owner") String owner, + /** Repository name, without the owner prefix or the `.git` suffix. */ + @JsonProperty("name") String name, + /** Host the remote points at, for example `github.com` or a GitHub Enterprise hostname. */ + @JsonProperty("host") String host +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitRemoteRepository.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitRemoteRepository.java new file mode 100644 index 0000000000..936e0f8159 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitRemoteRepository.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * A GitHub repository one of a working tree's remotes points at. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitRemoteRepository( + /** Account or organization owning the repository. */ + @JsonProperty("owner") String owner, + /** Repository name, without the owner. */ + @JsonProperty("name") String name, + /** GitHub host serving the repository, which is not `github.com` for a GitHub Enterprise remote. */ + @JsonProperty("host") String host, + /** Name of the first remote that produced this distinct repository entry, such as `origin` or `upstream`. */ + @JsonProperty("remoteName") String remoteName +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitReposFromRemotesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitReposFromRemotesParams.java new file mode 100644 index 0000000000..f9c351550f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitReposFromRemotesParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Git working tree whose GitHub remotes should be listed. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitReposFromRemotesParams( + /** Absolute path to the root of the git working tree. */ + @JsonProperty("gitRoot") String gitRoot +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitReposFromRemotesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitReposFromRemotesResult.java new file mode 100644 index 0000000000..cc62acf984 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitReposFromRemotesResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The GitHub repositories a working tree's remotes point at. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitReposFromRemotesResult( + /** One entry per distinct GitHub repository, in the order git reports the first remote for each repository. Empty when no remote points at a GitHub host, which a caller should read as `not connected to GitHub`. Failing to read the remotes is an error, not an empty list. */ + @JsonProperty("repositories") List repositories +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitWorkingDirectoryContextParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitWorkingDirectoryContextParams.java new file mode 100644 index 0000000000..17acdb64c3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitWorkingDirectoryContextParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Working-tree path a git query applies to. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GitWorkingDirectoryContextParams( + /** Absolute path to a directory inside the git working tree to query. */ + @JsonProperty("cwd") String cwd +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadForConfigDirParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadForConfigDirParams.java new file mode 100644 index 0000000000..a056698c92 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadForConfigDirParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory whose machine-wide state to read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GlobalStateLoadForConfigDirParams( + /** Copilot configuration directory to read the state document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. */ + @JsonProperty("configDir") String configDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java new file mode 100644 index 0000000000..9db799b57e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The host's machine-wide state. Every field is optional because a fresh install has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GlobalStateLoadResult( + /** Plugins installed on this machine. */ + @JsonProperty("installedPlugins") List installedPlugins, + /** Models the user selected recently, most recent first. */ + @JsonProperty("recentModelIds") List recentModelIds, + /** When the host first ran on this machine. */ + @JsonProperty("firstLaunchAt") String firstLaunchAt, + /** Terminals the user has already been asked to set up, so the host does not ask twice. */ + @JsonProperty("askedSetupTerminals") List askedSetupTerminals, + /** Folders where the user declined the init prompt, so it stays hidden there. */ + @JsonProperty("suppressInitFolders") List suppressInitFolders, + /** Whether the sandbox onboarding has been shown. */ + @JsonProperty("sandboxOnboardingShown") Boolean sandboxOnboardingShown, + /** Whether the user declined to trust the sandbox credential proxy CA. */ + @JsonProperty("sandboxCredentialProxyCaDeclined") Boolean sandboxCredentialProxyCaDeclined, + /** Whether the app tip has been shown. */ + @JsonProperty("appTipShown") Boolean appTipShown, + /** Whether the one-off cleanup of stored reasoning summaries has run. */ + @JsonProperty("reasoningSummariesCleanupDone") Boolean reasoningSummariesCleanupDone, + /** Account used for the most recent sign-in. */ + @JsonProperty("lastLoggedInUser") LoggedInUser lastLoggedInUser, + /** Every account the host has signed in to on this machine. */ + @JsonProperty("loggedInUsers") List loggedInUsers, + /** Whether the user is a GitHub or Microsoft staff member, which unlocks internal-only behavior. */ + @JsonProperty("staff") Boolean staff, + /** Whether the user was recognized as GitHub staff. */ + @JsonProperty("staffGithub") Boolean staffGitHub, + /** Whether the user was recognized as Microsoft staff. */ + @JsonProperty("staffMicrosoft") Boolean staffMicrosoft, + /** When the staff-only model reset last ran. */ + @JsonProperty("staffModelResetAt") String staffModelResetAt, + /** When the staff-only log level migration last ran. */ + @JsonProperty("staffLogLevelMigrationAt") String staffLogLevelMigrationAt, + /** When the staff-only update channel migration last ran. */ + @JsonProperty("staffUpdateChannelMigrationAt") String staffUpdateChannelMigrationAt, + /** Folders the user has marked as trusted. */ + @JsonProperty("trustedFolders") List trustedFolders, + /** When the Auto-feedback hint was last shown, as an ISO 8601 timestamp. It enforces the once-per-day cap for non-staff users across restarts. */ + @JsonProperty("autoFeedbackLastPromptedAt") String autoFeedbackLastPromptedAt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateWriteKeyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateWriteKeyParams.java new file mode 100644 index 0000000000..f6ee53a57b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateWriteKeyParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A single top-level key to record in the host's machine-wide state. The write replaces only that key and leaves the rest of the document untouched, so two writers recording different one-off flags do not overwrite each other. The stored credential keys cannot be written through this method. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record GlobalStateWriteKeyParams( + /** Copilot configuration directory to write the state document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to write the directory the server resolved for itself. Mirrors `globalState.loadForConfigDir`, so a caller can read and write the same directory. */ + @JsonProperty("configDir") String configDir, + /** Top-level key to write, named as it appears in the result of `globalState.load`. It must be one of the writable keys that `globalState.writeKey` lists. */ + @JsonProperty("key") String key, + /** Value to store for the key. Omit it, or pass null, to remove the key instead. */ + @JsonProperty("value") Object value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HooksDiscoverRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HooksDiscoverRequest.java new file mode 100644 index 0000000000..5d76a6d222 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HooksDiscoverRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths and host-exclusion behavior for server-scoped hook discovery. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class HooksDiscoverRequest { + + /** Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. */ + @JsonProperty("excludeHostHooks") + private Boolean excludeHostHooks; + + /** Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ + @JsonProperty("hookDirectories") + private List hookDirectories; + + /** + * Creates a request with its required inputs. + */ + public HooksDiscoverRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostHooks} property. + * + * @return When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. + */ + public Boolean getExcludeHostHooks() { + return excludeHostHooks; + } + + /** + * Returns the {@code hookDirectories} property. + * + * @return Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + public List getHookDirectories() { + return hookDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. + * @return this request + */ + public HooksDiscoverRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostHooks} property. + * + * @param value When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. + * @return this request + */ + public HooksDiscoverRequest setExcludeHostHooks(Boolean value) { + this.excludeHostHooks = value; + return this; + } + + /** + * Sets the {@code hookDirectories} property. + * + * @param value Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + * @return this request + */ + public HooksDiscoverRequest setHookDirectories(List value) { + this.hookDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostConfiguration.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostConfiguration.java index a9b392a8d1..15187b8763 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostConfiguration.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostConfiguration.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Normalized listener settings delivered only to the supervised hosting participant. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostCreateSessionParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostCreateSessionParams.java index 6c2233be78..348774f645 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostCreateSessionParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostCreateSessionParams.java @@ -29,6 +29,9 @@ record HostCreateSessionParams( @JsonProperty("handoffId") String handoffId, /** Resume an app-owned durable session instead of creating a new session. */ @JsonProperty("resume") Boolean resume, + /** For an explicit publication, borrow an existing owning-connection resident +instead of invoking the resume factory. Cold sessions still use the factory. */ + @JsonProperty("preferResident") Boolean preferResident, /** Host-selected SDK creation or resume settings, without executable callbacks or tools. */ @JsonProperty("config") Map config ) { diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEmptyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEmptyResult.java index 658f68f3b2..8c15b12414 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEmptyResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEmptyResult.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Empty acknowledgement for a completed host lifecycle operation. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEnvironmentCredentials.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEnvironmentCredentials.java index 51ad33c23b..607fc9db6c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEnvironmentCredentials.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostEnvironmentCredentials.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Private credentials delivered only to a runtime-owned Mission Control hosting participant. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitReason.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitReason.java index 28a5391b27..929ed09af7 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitReason.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitReason.java @@ -7,8 +7,17 @@ package com.github.copilot.generated.rpc; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; +/** + * Values for {@code HostExitReason}. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") public enum HostExitReason { /** The {@code disposed} variant. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitedNotification.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitedNotification.java index aa930eefe1..6c39e744c8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitedNotification.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostExitedNotification.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Reports a supervised listener's hosting-task termination and cleanup outcome. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostGitHubEnvironmentOptions.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostGitHubEnvironmentOptions.java index 065a9f9328..5a7f72d855 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostGitHubEnvironmentOptions.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostGitHubEnvironmentOptions.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * GitHub Mission Control registration options. The compute ID is application-owned and stable. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) @@ -24,6 +28,21 @@ public record HostGitHubEnvironmentOptions( /** Human-readable environment display name. */ @JsonProperty("name") String name, /** Stable application installation identity, reused across host restarts. */ - @JsonProperty("computeId") String computeId + @JsonProperty("computeId") String computeId, + /** Require sealed, connection-bound authentication (default true), independent of listener address. False permits unsealed direct credentials and unbound sealed relay credentials; use only when the caller fully controls and trusts the direct transport. Relay token encryption remains mandatory. */ + @JsonProperty("requireConnectionBinding") Boolean requireConnectionBinding ) { + + /** + * Creates environment options using the default connection-binding policy. + * + * @param name Human-readable environment display name. + * @param computeId Stable application installation identity, reused across host restarts. + */ + public HostGitHubEnvironmentOptions( + String name, + String computeId + ) { + this(name, computeId, null); + } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostListSessionsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostListSessionsParams.java new file mode 100644 index 0000000000..0e0c2472d0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostListSessionsParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Reads a running host's catalog or the runtime's saved default catalog. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record HostListSessionsParams( + /** Listener UUID returned by host.start; the caller must own it. Omit to read +the saved default compute-identity catalog without starting a listener. */ + @JsonProperty("hostId") String hostId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostListSessionsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostListSessionsResult.java new file mode 100644 index 0000000000..e430b96c29 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostListSessionsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The complete live and dormant advertised catalog, without subscribing to sessions. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record HostListSessionsResult( + /** Complete advertised session summaries, in the host's catalog order. */ + @JsonProperty("sessions") List sessions +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerConfiguration.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerConfiguration.java index 86f544e4ff..af868879ea 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerConfiguration.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerConfiguration.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Normalized local WebSocket listener settings. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerOptions.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerOptions.java index b85fe85722..7b3aae19e2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerOptions.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostLocalServerOptions.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Local WebSocket transport options. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostPublishSessionResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostPublishSessionResult.java index 3bad91e955..29c0600843 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostPublishSessionResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostPublishSessionResult.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * The existing runtime identity and its resource on the listener. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostRegisterSessionRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostRegisterSessionRequest.java index f431893e28..1346edb7b5 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostRegisterSessionRequest.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostRegisterSessionRequest.java @@ -10,14 +10,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.List; import javax.annotation.processing.Generated; /** * Listener-scoped registration, not a copy or durable adoption of a session. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateCallback.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateCallback.java index f35ea3d1a6..d609d096dc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateCallback.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateCallback.java @@ -10,14 +10,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import java.util.Map; import javax.annotation.processing.Generated; /** * Application callback routed over its existing SDK connection. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateResult.java index 96f0c87ec4..caf4f3e785 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionCreateResult.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * The resident session the application has materialized on its own connection. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionReleasedNotification.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionReleasedNotification.java index 6d06c6b9a6..a9266987c1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionReleasedNotification.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionReleasedNotification.java @@ -10,13 +10,17 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; import javax.annotation.processing.Generated; /** * Releases the original application session object retained for one handoff. * + * @apiNote This type is experimental and may change in a future version. + * * @since 1.0.0 */ +@CopilotExperimental @javax.annotation.processing.Generated("copilot-sdk-codegen") @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionSummary.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionSummary.java new file mode 100644 index 0000000000..e644a70e56 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostSessionSummary.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Metadata advertised by the AHP host, not a guarantee that history can be resumed. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record HostSessionSummary( + /** Stable AHP resource URI identifying the session on this host. */ + @JsonProperty("resource") String resource, + /** Authoritative title advertised by the host. */ + @JsonProperty("title") String title, + /** Session creation time as an ISO 8601 timestamp. */ + @JsonProperty("createdAt") String createdAt, + /** Last modification time as an ISO 8601 timestamp. */ + @JsonProperty("modifiedAt") String modifiedAt, + /** Unsigned 32-bit AHP session status bitset (0..=4294967295); unknown bits must be preserved. */ + @JsonProperty("status") Long status, + /** Optional activity description advertised by the host. */ + @JsonProperty("activity") String activity +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostStartRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostStartRequest.java new file mode 100644 index 0000000000..b6d4fc3b98 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HostStartRequest.java @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Starts a supervised AHP host with at least one explicitly selected transport. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class HostStartRequest { + + /** Caller-generated UUID identifying this connection-owned listener. */ + @JsonProperty("hostId") + private final String hostId; + + /** Enables a local WebSocket listener. */ + @JsonProperty("localServer") + private HostLocalServerOptions localServer; + + /** Registers a GitHub Mission Control environment and enables its relay transport. */ + @JsonProperty("githubEnvironment") + private HostGitHubEnvironmentOptions gitHubEnvironment; + + /** Ask the owning SDK application to materialize AHP sessions. */ + @JsonProperty("sessionFactory") + private Boolean sessionFactory; + + /** Ask the owning application to resume its durable AHP sessions. */ + @JsonProperty("resumeFactory") + private Boolean resumeFactory; + + /** Stable application identity selecting its durable host catalog. Defaults to the persisted runtime compute GUID; must agree with githubEnvironment.computeId when both are supplied. */ + @JsonProperty("computeId") + private String computeId; + + /** + * Creates a request with its required inputs. + * + * @param hostId Caller-generated UUID identifying this connection-owned listener. + */ + public HostStartRequest(String hostId) { + this.hostId = Objects.requireNonNull(hostId, "hostId"); + } + + /** + * Returns the {@code hostId} property. + * + * @return Caller-generated UUID identifying this connection-owned listener. + */ + public String getHostId() { + return hostId; + } + + /** + * Returns the {@code localServer} property. + * + * @return Enables a local WebSocket listener. + */ + public HostLocalServerOptions getLocalServer() { + return localServer; + } + + /** + * Returns the {@code githubEnvironment} property. + * + * @return Registers a GitHub Mission Control environment and enables its relay transport. + */ + public HostGitHubEnvironmentOptions getGitHubEnvironment() { + return gitHubEnvironment; + } + + /** + * Returns the {@code sessionFactory} property. + * + * @return Ask the owning SDK application to materialize AHP sessions. + */ + public Boolean getSessionFactory() { + return sessionFactory; + } + + /** + * Returns the {@code resumeFactory} property. + * + * @return Ask the owning application to resume its durable AHP sessions. + */ + public Boolean getResumeFactory() { + return resumeFactory; + } + + /** + * Returns the {@code computeId} property. + * + * @return Stable application identity selecting its durable host catalog. Defaults to the persisted runtime compute GUID; must agree with githubEnvironment.computeId when both are supplied. + */ + public String getComputeId() { + return computeId; + } + + /** + * Sets the {@code localServer} property. + * + * @param value Enables a local WebSocket listener. + * @return this request + */ + public HostStartRequest setLocalServer(HostLocalServerOptions value) { + this.localServer = value; + return this; + } + + /** + * Sets the {@code githubEnvironment} property. + * + * @param value Registers a GitHub Mission Control environment and enables its relay transport. + * @return this request + */ + public HostStartRequest setGitHubEnvironment(HostGitHubEnvironmentOptions value) { + this.gitHubEnvironment = value; + return this; + } + + /** + * Sets the {@code sessionFactory} property. + * + * @param value Ask the owning SDK application to materialize AHP sessions. + * @return this request + */ + public HostStartRequest setSessionFactory(Boolean value) { + this.sessionFactory = value; + return this; + } + + /** + * Sets the {@code resumeFactory} property. + * + * @param value Ask the owning application to resume its durable AHP sessions. + * @return this request + */ + public HostStartRequest setResumeFactory(Boolean value) { + this.resumeFactory = value; + return this; + } + + /** + * Sets the {@code computeId} property. + * + * @param value Stable application identity selecting its durable host catalog. Defaults to the persisted runtime compute GUID; must agree with githubEnvironment.computeId when both are supplied. + * @return this request + */ + public HostStartRequest setComputeId(String value) { + this.computeId = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRepoSourcesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRepoSourcesParams.java new file mode 100644 index 0000000000..5aee113bf8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRepoSourcesParams.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record InstructionsDiscoverRepoSourcesParams( + /** Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. */ + @JsonProperty("location") String location, + /** When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. */ + @JsonProperty("isCli") Boolean isCli, + /** Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. */ + @JsonProperty("cwdPath") String cwdPath, + /** Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. */ + @JsonProperty("configDir") String configDir, + /** Extra directories to scan alongside instruction directories configured in the runtime environment. */ + @JsonProperty("additionalDirs") List additionalDirs, + /** When true, also discover instruction files nested below the location. */ + @JsonProperty("enableChildInstructions") Boolean enableChildInstructions +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRequest.java new file mode 100644 index 0000000000..34175da41b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include in instruction discovery. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class InstructionsDiscoverRequest { + + /** Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. */ + @JsonProperty("excludeHostInstructions") + private Boolean excludeHostInstructions; + + /** Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ + @JsonProperty("instructionDirectories") + private List instructionDirectories; + + /** + * Creates a request with its required inputs. + */ + public InstructionsDiscoverRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostInstructions} property. + * + * @return When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + */ + public Boolean getExcludeHostInstructions() { + return excludeHostInstructions; + } + + /** + * Returns the {@code instructionDirectories} property. + * + * @return Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + public List getInstructionDirectories() { + return instructionDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + * @return this request + */ + public InstructionsDiscoverRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostInstructions} property. + * + * @param value When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + * @return this request + */ + public InstructionsDiscoverRequest setExcludeHostInstructions(Boolean value) { + this.excludeHostInstructions = value; + return this; + } + + /** + * Sets the {@code instructionDirectories} property. + * + * @param value Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + * @return this request + */ + public InstructionsDiscoverRequest setInstructionDirectories(List value) { + this.instructionDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsGetDiscoveryPathsRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsGetDiscoveryPathsRequest.java new file mode 100644 index 0000000000..fc328be97e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsGetDiscoveryPathsRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include when enumerating instruction discovery targets. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class InstructionsGetDiscoveryPathsRequest { + + /** Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). */ + @JsonProperty("excludeHostInstructions") + private Boolean excludeHostInstructions; + + /** Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. */ + @JsonProperty("instructionDirectories") + private List instructionDirectories; + + /** + * Creates a request with its required inputs. + */ + public InstructionsGetDiscoveryPathsRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostInstructions} property. + * + * @return When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + */ + public Boolean getExcludeHostInstructions() { + return excludeHostInstructions; + } + + /** + * Returns the {@code instructionDirectories} property. + * + * @return Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + public List getInstructionDirectories() { + return instructionDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + * @return this request + */ + public InstructionsGetDiscoveryPathsRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostInstructions} property. + * + * @param value When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + * @return this request + */ + public InstructionsGetDiscoveryPathsRequest setExcludeHostInstructions(Boolean value) { + this.excludeHostInstructions = value; + return this; + } + + /** + * Sets the {@code instructionDirectories} property. + * + * @param value Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + * @return this request + */ + public InstructionsGetDiscoveryPathsRequest setInstructionDirectories(List value) { + this.instructionDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsInitPromptResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsInitPromptResult.java new file mode 100644 index 0000000000..20eb197498 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsInitPromptResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The prompt the init command runs. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record InstructionsInitPromptResult( + /** Prompt text authoring repository instructions. */ + @JsonProperty("prompt") String prompt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LocationPermissionsCleanupResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LocationPermissionsCleanupResult.java new file mode 100644 index 0000000000..ea8b72d7aa --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LocationPermissionsCleanupResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Which stored location permissions were dropped because their directory is gone. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record LocationPermissionsCleanupResult( + /** Location keys whose grants were removed. Empty when every stored location still exists. */ + @JsonProperty("removedLocationKeys") List removedLocationKeys +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LoggedInUser.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LoggedInUser.java new file mode 100644 index 0000000000..ebd6526dc4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LoggedInUser.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * An account the host has signed in to, identified by the server it lives on and the login it uses there. The same person can appear more than once when they use both github.com and an Enterprise server. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record LoggedInUser( + /** Host the account belongs to, such as `github.com` or an Enterprise server. */ + @JsonProperty("host") String host, + /** Account login on that host. */ + @JsonProperty("login") String login, + /** Account kind, when the host recorded one. Consumers must tolerate new strings. */ + @JsonProperty("kind") String kind, + /** Source account this account was derived from, when one was recorded. */ + @JsonProperty("derivedFrom") String derivedFrom +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionEvaluation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionEvaluation.java new file mode 100644 index 0000000000..40f74da843 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionEvaluation.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPermissionEvaluation( + /** Original input operation associated with this verdict. */ + @JsonProperty("operation") ManagedPermissionOperation operation, + /** Managed-policy decision only; never bypasses user permissions or other security controls. */ + @JsonProperty("verdict") ManagedPermissionVerdict verdict +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionOperation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionOperation.java new file mode 100644 index 0000000000..ba60365d3c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionOperation.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPermissionOperation( + /** Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. */ + @JsonProperty("url") String url, + /** Operation to evaluate. Currently only url is supported. */ + @JsonProperty("kind") ManagedPermissionOperationKind kind +) { + + /** Operation to evaluate. Currently only url is supported. */ + public enum ManagedPermissionOperationKind { + /** The {@code url} variant. */ + URL("url"); + + private final String value; + ManagedPermissionOperationKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedPermissionOperationKind fromValue(String value) { + for (ManagedPermissionOperationKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedPermissionOperationKind value: " + value); + } + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionVerdict.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionVerdict.java new file mode 100644 index 0000000000..1254c36718 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionVerdict.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ManagedPermissionVerdict { + /** The {@code deny} variant. */ + DENY("deny"), + /** The {@code ask} variant. */ + ASK("ask"), + /** The {@code allow} variant. */ + ALLOW("allow"), + /** The {@code unmanaged} variant. */ + UNMANAGED("unmanaged"); + + private final String value; + ManagedPermissionVerdict(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedPermissionVerdict fromValue(String value) { + for (ManagedPermissionVerdict v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedPermissionVerdict value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryEntry.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryEntry.java new file mode 100644 index 0000000000..9fb16e5a55 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryEntry.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Retry outcome for one plugin required by managed settings. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPluginRetryEntry( + /** Plugin spec in "plugin@marketplace" form. */ + @JsonProperty("spec") String spec, + /** What the retry did for this plugin. */ + @JsonProperty("status") ManagedPluginRetryStatus status, + /** Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. */ + @JsonProperty("error") String error +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryStatus.java new file mode 100644 index 0000000000..43a46d2625 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryStatus.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * What retrying did for one plugin required by managed settings. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ManagedPluginRetryStatus { + /** The {@code installed} variant. */ + INSTALLED("installed"), + /** The {@code updated} variant. */ + UPDATED("updated"), + /** The {@code already_present} variant. */ + ALREADY_PRESENT("already_present"), + /** The {@code failed} variant. */ + FAILED("failed"), + /** The {@code deferred} variant. */ + DEFERRED("deferred"), + /** The {@code not_required} variant. */ + NOT_REQUIRED("not_required"); + + private final String value; + ManagedPluginRetryStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedPluginRetryStatus fromValue(String value) { + for (ManagedPluginRetryStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedPluginRetryStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingMeta.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingMeta.java index 46967ea441..3a2bf1fd0b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingMeta.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingMeta.java @@ -28,6 +28,8 @@ public record ManagedSettingMeta( /** Whether users and repositories may choose a different value. `false` means policy locks the value. */ @JsonProperty("overridable") Boolean overridable, /** Channel that supplied this scalar value, matching a `layers[].source`: `device`, `server`, or `policyHelper`. These scalar defaults select one winning channel, not a mixed source. Treat unknown values as additional channels; more may be added. */ - @JsonProperty("source") String source + @JsonProperty("source") String source, + /** Original managed value when the runtime adjusted it to a supported effective value. Omitted when no adjustment was needed. */ + @JsonProperty("requested") String requested ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsParams.java new file mode 100644 index 0000000000..fa5802b6f7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A user settings document and the effective managed policy whose controlled entries should be stamped onto it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsApplyControlsParams( + /** The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings, + /** The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. */ + @JsonProperty("managed") Object managed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsResult.java new file mode 100644 index 0000000000..c5a85c72bb --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The user settings with the managed layer's controlled entries stamped on. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsApplyControlsResult( + /** The resulting settings document. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassDisableSource.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassDisableSource.java new file mode 100644 index 0000000000..f2f64e075f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassDisableSource.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Which layer disabled bypass-permissions mode. The layer matters because only a server-delivered disable is pinned to an account and can later be lifted by signing in elsewhere. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsBypassDisableSource { + /** The {@code user} variant. */ + USER("user"), + /** The {@code managed} variant. */ + MANAGED("managed"), + /** The {@code mdm} variant. */ + MDM("mdm"); + + private final String value; + ManagedSettingsBypassDisableSource(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsBypassDisableSource fromValue(String value) { + for (ManagedSettingsBypassDisableSource v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsBypassDisableSource value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassPolicyResolution.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassPolicyResolution.java new file mode 100644 index 0000000000..3101cf80fd --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassPolicyResolution.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the managed-policy resolution said about bypass-permissions mode. `unknown` is a third answer rather than a missing one, and the caller must send it explicitly when it has no verdict. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsBypassPolicyResolution { + /** The {@code allowed} variant. */ + ALLOWED("allowed"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ManagedSettingsBypassPolicyResolution(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsBypassPolicyResolution fromValue(String value) { + for (ManagedSettingsBypassPolicyResolution v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsBypassPolicyResolution value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestParams.java new file mode 100644 index 0000000000..78e71c35cf --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestParams.java @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Inputs describing the host and account an ingestion should resolve managed policy for. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsIngestParams( + /** The policy-helper invocation reason. Defaults to sessionStart. */ + @JsonProperty("policyHelperReason") ManagedSettingsPolicyHelperReason policyHelperReason, + /** Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ + @JsonProperty("selfFetch") Boolean selfFetch, + /** The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. */ + @JsonProperty("authInfo") Object authInfo, + /** The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. */ + @JsonProperty("sessionId") String sessionId, + /** A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. */ + @JsonProperty("hasDeviceResponse") Boolean hasDeviceResponse, + /** Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. */ + @JsonProperty("bypassCacheRead") Boolean bypassCacheRead, + /** How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. */ + @JsonProperty("serverPolicyCacheMode") ManagedSettingsServerPolicyCacheMode serverPolicyCacheMode, + /** Whether a configured platform policy helper may be run to produce an enforced helper layer. */ + @JsonProperty("policyHelperEnabled") Boolean policyHelperEnabled, + /** Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. */ + @JsonProperty("policyHelperWorkingDirectory") String policyHelperWorkingDirectory, + /** User agent to send with the policy fetch. */ + @JsonProperty("userAgent") String userAgent, + /** Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. */ + @JsonProperty("clientName") String clientName, + /** The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment, + /** The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. */ + @JsonProperty("platform") String platform, + /** The host's home directory, used to resolve cache and managed-file locations. */ + @JsonProperty("homeDirectory") String homeDirectory +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestResult.java new file mode 100644 index 0000000000..d5372cf860 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestResult.java @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsIngestResult( + /** The effective managed settings composed from every resolved layer. Omitted when no layer set anything, so an unmanaged host locks nothing. */ + @JsonProperty("settings") Object settings, + /** The effective managed permissions layer, when the resolved policy carries one. */ + @JsonProperty("permissions") Object permissions, + /** The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. */ + @JsonProperty("serverFetchFailed") Boolean serverFetchFailed, + /** No usable token was available, so no server fetch was attempted. */ + @JsonProperty("serverTokenUnavailable") Boolean serverTokenUnavailable, + /** The error that made the server fetch fail, when one did. */ + @JsonProperty("serverFetchError") String serverFetchError, + /** How the server layer was resolved. */ + @JsonProperty("serverResolution") ManagedSettingsServerPolicyResolution serverResolution, + /** The server fetch failed in a way a later retry could succeed at, as opposed to a refusal that no retry will change. */ + @JsonProperty("serverRetryableFailure") Boolean serverRetryableFailure, + /** A live fetch failed but a recent cached entry was served in its place, so `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a cache-backed fallback. */ + @JsonProperty("serverCacheFallback") Boolean serverCacheFallback, + /** A server-managed policy is known to exist even though `serverResponse` is intentionally unset. Consumers should OR this with the presence of `serverResponse` when deciding whether the device is managed, so a fresh start during an outage still applies the fail-closed gates instead of treating the device as unmanaged. */ + @JsonProperty("serverSourceFound") Boolean serverSourceFound, + /** The account's server-delivered policy, when one was resolved. */ + @JsonProperty("serverResponse") Object serverResponse, + /** The sandbox object from a cached server policy that a forced refresh declined to serve in full. Folded back into the effective sandbox layer so an outage during a forced refresh still synthesizes the fail-closed sandbox floor from the administrator's known intent. */ + @JsonProperty("serverSandboxFloor") Object serverSandboxFloor, + /** The server fetch failed while a policy demanded a fresh confirmation, which is the strict posture an enterprise opted into rather than an ordinary transient failure. */ + @JsonProperty("serverForcedRefreshFailure") Boolean serverForcedRefreshFailure, + /** The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. Gates that exist only because of managed policy should deny on this rather than falling back to their unmanaged default. */ + @JsonProperty("serverClientUpdateRequired") String serverClientUpdateRequired, + /** Minimum client version requested by a successful response. Advisory only; the delivered policy remains active. */ + @JsonProperty("serverClientUpdateRequested") String serverClientUpdateRequested, + /** The synthesized fail-closed permissions layer applied in place of a policy a refused client may not enforce. */ + @JsonProperty("serverPermissionsFloor") Object serverPermissionsFloor, + /** The device layer discovered from the machine, when one exists. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** The device layer could not be read, so it is unconfirmed rather than known-absent. */ + @JsonProperty("deviceLoadFailed") Boolean deviceLoadFailed, + /** The sandbox floor contributed by the device layer. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** A device-managed policy is known to exist. */ + @JsonProperty("deviceSourceFound") Boolean deviceSourceFound, + /** Whether the device layer's sandbox intent could not be determined, so a consumer must not read its absence as permission to run unsandboxed. */ + @JsonProperty("deviceSandboxUndetermined") Boolean deviceSandboxUndetermined, + /** The layer produced by the platform policy helper, when one ran. */ + @JsonProperty("policyHelperResponse") Object policyHelperResponse, + /** Which channel registered the policy helper that produced the helper layer. */ + @JsonProperty("policyHelperAuthority") ManagedSettingsPolicyHelperAuthority policyHelperAuthority, + /** The policy helper was configured but could not be run or its output could not be read. */ + @JsonProperty("policyHelperLoadFailed") Boolean policyHelperLoadFailed, + /** A policy helper is configured for this host. */ + @JsonProperty("policyHelperConfigured") Boolean policyHelperConfigured, + /** The policy helper's failure must be treated as fail-closed rather than ignored. */ + @JsonProperty("policyHelperFailClosed") Boolean policyHelperFailClosed, + /** Diagnostics emitted while resolving the layers, in the order they occurred. */ + @JsonProperty("logMessages") List logMessages +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlParams.java new file mode 100644 index 0000000000..ff434c10ae --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlParams.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsLoadRemoteControlParams( + /** The policy-helper invocation reason. Defaults to sessionStart. */ + @JsonProperty("policyHelperReason") ManagedSettingsPolicyHelperReason policyHelperReason, + /** Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ + @JsonProperty("selfFetch") Boolean selfFetch, + /** The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. */ + @JsonProperty("authInfo") Object authInfo, + /** A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. */ + @JsonProperty("hasDeviceResponse") Boolean hasDeviceResponse, + /** Whether a configured platform policy helper may be run to produce an enforced helper layer. */ + @JsonProperty("policyHelperEnabled") Boolean policyHelperEnabled, + /** User agent to send with the policy fetch. */ + @JsonProperty("userAgent") String userAgent, + /** Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. */ + @JsonProperty("clientName") String clientName, + /** The host's environment variables, read for cache location and policy overrides. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment, + /** The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. */ + @JsonProperty("platform") String platform, + /** The host's home directory, used to resolve cache and managed-file locations. */ + @JsonProperty("homeDirectory") String homeDirectory +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlResult.java new file mode 100644 index 0000000000..2acf5180c5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsLoadRemoteControlResult( + /** The account's `remoteControl` policy document. Absent when no managed policy governs remote control for this account. Reported as an explicit disabled policy, rather than as absence, when the service refused to deliver a policy this client is too old to enforce. */ + @JsonProperty("remoteControl") Object remoteControl +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogLevel.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogLevel.java new file mode 100644 index 0000000000..1775a5db19 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogLevel.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Severity of a diagnostic emitted while ingesting managed settings. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsLogLevel { + /** The {@code debug} variant. */ + DEBUG("debug"), + /** The {@code info} variant. */ + INFO("info"), + /** The {@code warning} variant. */ + WARNING("warning"), + /** The {@code error} variant. */ + ERROR("error"); + + private final String value; + ManagedSettingsLogLevel(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsLogLevel fromValue(String value) { + for (ManagedSettingsLogLevel v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsLogLevel value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogMessage.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogMessage.java new file mode 100644 index 0000000000..be859afde3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogMessage.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One diagnostic emitted while ingesting managed settings. Returned rather than logged by the runtime so the host decides where ingestion diagnostics go, which matters because an ingestion runs before a session exists to carry a log sink. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsLogMessage( + /** Severity of this diagnostic. */ + @JsonProperty("level") ManagedSettingsLogLevel level, + /** Human-readable diagnostic text. */ + @JsonProperty("message") String message +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsMeta.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsMeta.java index 7348141749..d98d081e63 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsMeta.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsMeta.java @@ -28,6 +28,10 @@ public record ManagedSettingsMeta( /** Lock state and provenance of `values.model`. */ @JsonProperty("model") ManagedSettingMeta model, /** Lock state and provenance of `values.autoTier`. */ - @JsonProperty("autoTier") ManagedSettingMeta autoTier + @JsonProperty("autoTier") ManagedSettingMeta autoTier, + /** Lock state and provenance of `values.effortLevel`. */ + @JsonProperty("effortLevel") ManagedSettingMeta effortLevel, + /** Lock state and provenance of `values.contextTier`. */ + @JsonProperty("contextTier") ManagedSettingMeta contextTier ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueParams.java new file mode 100644 index 0000000000..27effeabae --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsParseClientValueParams( + /** The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. */ + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueResult.java new file mode 100644 index 0000000000..695248ea4a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The accepted managed settings, reduced to the keys a client is allowed to set. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsParseClientValueResult( + /** The normalized settings. Omitted when the client supplied none. An accepted document that sets nothing comes back as an empty object, which is distinct from omission. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateParams.java new file mode 100644 index 0000000000..0a5d0c53ab --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Managed policy context and ordered operations for pure, sessionless evaluation. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedSettingsPermissionsEvaluateParams( + /** Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. */ + @JsonProperty("context") ManagedPermissionsContext context, + /** Operations to evaluate, preserving input order and duplicates. An empty batch is valid. */ + @JsonProperty("operations") List operations +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateResult.java new file mode 100644 index 0000000000..099a216b48 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateResult.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Ordered managed permission verdicts and the supplied policy's fail-closed posture. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedSettingsPermissionsEvaluateResult( + /** One verdict per input operation, in the same order, including duplicates. */ + @JsonProperty("results") List results, + /** Managed permission policy could not be determined; every operation is denied. */ + @JsonProperty("failClosed") Boolean failClosed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperAuthority.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperAuthority.java new file mode 100644 index 0000000000..34b33ad56f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperAuthority.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Which channel registered the policy helper that produced a helper layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsPolicyHelperAuthority { + /** The {@code device} variant. */ + DEVICE("device"), + /** The {@code server} variant. */ + SERVER("server"); + + private final String value; + ManagedSettingsPolicyHelperAuthority(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsPolicyHelperAuthority fromValue(String value) { + for (ManagedSettingsPolicyHelperAuthority v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsPolicyHelperAuthority value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperReason.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperReason.java new file mode 100644 index 0000000000..509e98f5e7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperReason.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * The operation that requires a policy-helper response. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsPolicyHelperReason { + /** The {@code sessionStart} variant. */ + SESSIONSTART("sessionStart"), + /** The {@code pluginActivation} variant. */ + PLUGINACTIVATION("pluginActivation"); + + private final String value; + ManagedSettingsPolicyHelperReason(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsPolicyHelperReason fromValue(String value) { + for (ManagedSettingsPolicyHelperReason v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsPolicyHelperReason value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsReadDeviceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsReadDeviceResult.java new file mode 100644 index 0000000000..880044dc83 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsReadDeviceResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsReadDeviceResult( + /** Validated, canonical device-managed settings. Omitted when no device policy was discovered, when the discovered document failed validation, or when it validated to an empty object — an empty document carries no policy, and reporting it as present would outrank layers that do. */ + @JsonProperty("settings") Object settings, + /** Sandbox floor read from the discovered document before validation, so a document that is otherwise rejected can still raise the floor it declared. */ + @JsonProperty("sandboxFloor") Object sandboxFloor, + /** Whether discovery or validation failed. A host must treat this as "policy unknown" rather than "no policy": absent settings with this set false mean the device genuinely has none. */ + @JsonProperty("loadFailed") Boolean loadFailed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionParams.java new file mode 100644 index 0000000000..3b56f24c92 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionParams.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveBypassDisableTransitionParams( + /** Which layer currently disables bypass mode. Omit it when nothing does. */ + @JsonProperty("currentSource") ManagedSettingsBypassDisableSource currentSource, + /** The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. */ + @JsonProperty("currentManagedIdentity") String currentManagedIdentity, + /** The account signed in now. A `managed` disable pinned to a different account is lifted. */ + @JsonProperty("activeIdentity") String activeIdentity, + /** What the resolution said about bypass mode. Send `unknown` rather than omitting the field when there is no verdict. */ + @JsonProperty("policy") ManagedSettingsBypassPolicyResolution policy +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionResult.java new file mode 100644 index 0000000000..2557cd5cb3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionResult.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The bypass-permissions state a host should hold after the resolution, and what it must do to get there. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveBypassDisableTransitionResult( + /** Which layer disables bypass mode after this resolution. Omitted when none does, which is what a lifted disable looks like. */ + @JsonProperty("source") ManagedSettingsBypassDisableSource source, + /** The account the returned `managed` source is pinned to. Store it alongside `source`; the next call needs it to decide whether an account switch lifts the disable. */ + @JsonProperty("managedIdentity") String managedIdentity, + /** The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly as it is, which is not the same as being told to store `false`. */ + @JsonProperty("setDisabledState") Boolean setDisabledState, + /** Whether a bypass-permissions session already running must be turned off. True only when this resolution newly disables bypass mode, so a host that is already compliant is not interrupted. */ + @JsonProperty("suppressRuntimeAllowAll") Boolean suppressRuntimeAllowAll +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveDeviceForceLoginOrgsGateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveDeviceForceLoginOrgsGateParams.java new file mode 100644 index 0000000000..75b89cb8bd --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveDeviceForceLoginOrgsGateParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The credential and environment to evaluate the device-channel sign-in pin against. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveDeviceForceLoginOrgsGateParams( + /** The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. */ + @JsonProperty("authInfo") Object authInfo, + /** The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueParams.java new file mode 100644 index 0000000000..7e82bf0b3c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueParams.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveEffectiveValueParams( + /** The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. */ + @JsonProperty("server") Object server, + /** The device layer: native MDM and managed-file settings describing the machine rather than the account. */ + @JsonProperty("mdm") Object mdm, + /** The device sandbox floor, folded into the device layer under `sandbox` before composition. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** The policy-helper layer, an enforced channel sourced from a platform policy helper process. */ + @JsonProperty("policyHelper") Object policyHelper +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueResult.java new file mode 100644 index 0000000000..441bb9039f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The effective managed policy composed from the supplied layers. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveEffectiveValueResult( + /** The composed effective managed settings. Omitted when no layer sets anything, so an unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an advisory server force-on was dropped because this host cannot run the sandbox. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveParams.java index ffb5af2b18..1ecc14a56c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveParams.java @@ -29,6 +29,23 @@ public record ManagedSettingsResolveParams( /** GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. */ @JsonProperty("gitHubToken") String gitHubToken, /** Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. */ - @JsonProperty("clientName") String clientName + @JsonProperty("clientName") String clientName, + /** Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. */ + @JsonProperty("workingDirectory") String workingDirectory ) { + + /** + * Creates managed-settings resolution parameters without a working directory. + * + * @param selectionId Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. + * @param gitHubToken GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. + * @param clientName Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. + */ + public ManagedSettingsResolveParams( + String selectionId, + String gitHubToken, + String clientName + ) { + this(selectionId, gitHubToken, clientName, null); + } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java index 6d9941f4a9..d13b9a555b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; import java.util.List; import javax.annotation.processing.Generated; @@ -25,6 +26,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record ManagedSettingsResolveResult( + /** Reusable source-composed permission policy for managedSettings.permissions.evaluate. Unlike resolved.settings.permissions, this retains every source's allowlist and default-prompt semantics. Refresh through resolve when account/device policy changes. Absent on runtimes that do not support permission evaluation. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. */ @JsonProperty("account") String account, /** Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyParams.java new file mode 100644 index 0000000000..e0074bb8bc --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyParams.java @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveStartupPolicyParams( + /** The policy-helper invocation reason. Defaults to sessionStart. */ + @JsonProperty("policyHelperReason") ManagedSettingsPolicyHelperReason policyHelperReason, + /** Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ + @JsonProperty("selfFetch") Boolean selfFetch, + /** The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. */ + @JsonProperty("authInfo") Object authInfo, + /** The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. */ + @JsonProperty("sessionId") String sessionId, + /** A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. */ + @JsonProperty("hasDeviceResponse") Boolean hasDeviceResponse, + /** Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. */ + @JsonProperty("bypassCacheRead") Boolean bypassCacheRead, + /** How this resolution may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two express the same decision and accepting both would leave the caller unsure which one the runtime honored. */ + @JsonProperty("serverPolicyCacheMode") ManagedSettingsServerPolicyCacheMode serverPolicyCacheMode, + /** Whether a configured platform policy helper may be run to produce an enforced helper layer. */ + @JsonProperty("policyHelperEnabled") Boolean policyHelperEnabled, + /** Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. */ + @JsonProperty("policyHelperWorkingDirectory") String policyHelperWorkingDirectory, + /** User agent to send with the policy fetch. */ + @JsonProperty("userAgent") String userAgent, + /** Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. */ + @JsonProperty("clientName") String clientName, + /** The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment, + /** The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. */ + @JsonProperty("platform") String platform, + /** The host's home directory, used to resolve cache and managed-file locations. */ + @JsonProperty("homeDirectory") String homeDirectory, + /** Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. */ + @JsonProperty("retainAndApply") Boolean retainAndApply +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyResult.java new file mode 100644 index 0000000000..69def35f89 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyResult.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveStartupPolicyResult( + /** How the current runtime resolved the server layer. */ + @JsonProperty("serverResolution") ManagedSettingsServerPolicyResolution serverResolution, + /** Advisory minimum client version from a successful server response. */ + @JsonProperty("clientUpdateRequested") String clientUpdateRequested, + /** The account's server-delivered policy, when one was resolved. */ + @JsonProperty("serverResponse") Object serverResponse, + /** The device layer discovered from the machine, when one exists. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** The sandbox floor contributed by the device layer. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** The layer produced by the platform policy helper, when one ran. */ + @JsonProperty("policyHelperResponse") Object policyHelperResponse, + /** The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. */ + @JsonProperty("serverFetchFailed") Boolean serverFetchFailed, + /** The device layer could not be read, so it is unconfirmed rather than known-absent. */ + @JsonProperty("deviceLoadFailed") Boolean deviceLoadFailed, + /** The policy helper was configured but could not be run, or its output could not be read. */ + @JsonProperty("policyHelperLoadFailed") Boolean policyHelperLoadFailed, + /** Telemetry describing which layers answered and how, for the host to report alongside its own startup events. */ + @JsonProperty("telemetry") Object telemetry, + /** The effective sandbox floor composed across every layer, which a host must apply rather than its own default. */ + @JsonProperty("sandboxFloor") Object sandboxFloor, + /** Some layer of the policy could not be confirmed, so its absence must not be read as permission. Folds in a failed server fetch as well as an unreadable device layer. */ + @JsonProperty("policyUndetermined") Boolean policyUndetermined, + /** The permissions layer specifically could not be confirmed, so permission gates apply their fail-closed posture. */ + @JsonProperty("permissionPolicyUndetermined") Boolean permissionPolicyUndetermined, + /** A managed policy is known to apply to this host, from a discovered source or a resolved document. */ + @JsonProperty("managedPolicyPresent") Boolean managedPolicyPresent, + /** The sandbox was enabled because policy could not be confirmed rather than because an administrator asked for it. Lets a host explain a sandbox the user did not configure. */ + @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, + /** The enterprise sign-in verdict for the credential this resolution ran against, evaluated over the effective policy so a server-delivered pin is honored alongside a device one. Computed on every resolution, including one that was not retained, so a host that declines to apply policy still cannot proceed past a pin. */ + @JsonProperty("forceLoginOrgs") ForceLoginOrgsDecision forceLoginOrgs, + /** The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. */ + @JsonProperty("clientUpdateRequired") String clientUpdateRequired, + /** Warnings raised while resolving, in the order they occurred. */ + @JsonProperty("warnings") List warnings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java index 2020e9d434..aaef086d58 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; import java.util.List; import javax.annotation.processing.Generated; @@ -26,6 +27,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record ManagedSettingsResolvedData( + /** Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. */ @JsonProperty("source") ManagedSettingsResolvedSource source, /** Whether the server (account/org) managed-settings layer was present */ @@ -36,11 +39,11 @@ public record ManagedSettingsResolvedData( @JsonProperty("clientManaged") Boolean clientManaged, /** Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. */ @JsonProperty("policyHelperManaged") Boolean policyHelperManaged, - /** Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. */ + /** Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. */ @JsonProperty("failClosed") Boolean failClosed, /** Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. */ @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, - /** Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. */ + /** Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. */ @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, /** Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. */ @JsonProperty("permissionsAllowIntersected") Boolean permissionsAllowIntersected, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsRetainPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsRetainPolicyParams.java new file mode 100644 index 0000000000..5ea352e817 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsRetainPolicyParams.java @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed layers to retain as this process's startup policy, with the outcome of fetching each one. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsRetainPolicyParams( + /** The resolved server policy. A known source can lack a response after a forced-refresh failure. */ + @JsonProperty("serverResponse") Object serverResponse, + /** The device/MDM policy layer. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. */ + @JsonProperty("deviceSourceFound") Boolean deviceSourceFound, + /** Whether any managed policy source exists, independently of fetch failures. */ + @JsonProperty("managedPolicyPresent") Boolean managedPolicyPresent, + /** Whether the server policy source exists, even when its response is unavailable. */ + @JsonProperty("serverSourceFound") Boolean serverSourceFound, + /** Whether a required fresh server-policy confirmation failed. */ + @JsonProperty("serverForcedRefreshFailure") Boolean serverForcedRefreshFailure, + /** Preserve the retained server layer during a device-only resolution. */ + @JsonProperty("preserveServerState") Boolean preserveServerState, + /** Whether the device sandbox intent is unreadable independently of its other settings. */ + @JsonProperty("deviceSandboxUndetermined") Boolean deviceSandboxUndetermined, + /** Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. */ + @JsonProperty("sandboxFloorUndetermined") Boolean sandboxFloorUndetermined, + /** Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. */ + @JsonProperty("permissionPolicyUndetermined") Boolean permissionPolicyUndetermined, + /** Whether uncertainty alone enabled the shared sandbox floor. */ + @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, + /** Shared server/device sandbox floor, excluding session-local helper policy. */ + @JsonProperty("sharedSandboxFloor") Object sharedSandboxFloor, + /** Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. */ + @JsonProperty("serverFetchFailed") Boolean serverFetchFailed, + /** Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. */ + @JsonProperty("deviceLoadFailed") Boolean deviceLoadFailed, + /** The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. */ + @JsonProperty("policyHelperResponse") Object policyHelperResponse +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyCacheMode.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyCacheMode.java new file mode 100644 index 0000000000..7258e376b5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyCacheMode.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * How an ingestion may use the on-disk server-policy cache. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsServerPolicyCacheMode { + /** The {@code preferFresh} variant. */ + PREFERFRESH("preferFresh"), + /** The {@code cacheOnly} variant. */ + CACHEONLY("cacheOnly"), + /** The {@code fallbackOnly} variant. */ + FALLBACKONLY("fallbackOnly"), + /** The {@code disabled} variant. */ + DISABLED("disabled"); + + private final String value; + ManagedSettingsServerPolicyCacheMode(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsServerPolicyCacheMode fromValue(String value) { + for (ManagedSettingsServerPolicyCacheMode v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsServerPolicyCacheMode value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyResolution.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyResolution.java new file mode 100644 index 0000000000..8315739063 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyResolution.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * How the server layer of an ingestion was resolved. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsServerPolicyResolution { + /** The {@code live} variant. */ + LIVE("live"), + /** The {@code freshCache} variant. */ + FRESHCACHE("freshCache"), + /** The {@code cacheMiss} variant. */ + CACHEMISS("cacheMiss"), + /** The {@code fallbackCache} variant. */ + FALLBACKCACHE("fallbackCache"), + /** The {@code failOpen} variant. */ + FAILOPEN("failOpen"), + /** The {@code failClosed} variant. */ + FAILCLOSED("failClosed"), + /** The {@code skippedNoToken} variant. */ + SKIPPEDNOTOKEN("skippedNoToken"); + + private final String value; + ManagedSettingsServerPolicyResolution(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsServerPolicyResolution fromValue(String value) { + for (ManagedSettingsServerPolicyResolution v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsServerPolicyResolution value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java index 32879f689c..40a4e02992 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java @@ -25,6 +25,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) public record ManagedSettingsValidateParams( /** The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("content") Object content, /** Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. */ @JsonProperty("layer") String layer diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValues.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValues.java index 931294b19c..a9094de7ca 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValues.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValues.java @@ -25,9 +25,13 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record ManagedSettingsValues( - /** Managed default model identifier, as configured. New sessions start with it; it can name a model the account cannot use, so hosts match it against the listed models. */ + /** Managed default model identifier. When model availability was resolved, aliases and family names are projected to a concrete available model ID; otherwise the configured value is returned. */ @JsonProperty("model") String model, /** Managed Auto routing preference, used when the selected model is `auto`. */ - @JsonProperty("autoTier") AutoTier autoTier + @JsonProperty("autoTier") AutoTier autoTier, + /** Managed reasoning-effort default for the managed concrete model. The runtime clamps it to an entitled effort when model availability is known. */ + @JsonProperty("effortLevel") String effortLevel, + /** Managed context-tier default for the managed concrete model. */ + @JsonProperty("contextTier") ContextTier contextTier ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpConfiguredServer.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpConfiguredServer.java new file mode 100644 index 0000000000..4e37d915f8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpConfiguredServer.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Effective MCP configuration entry. Configuration enablement is distinct from the optional live observation. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpConfiguredServer( + /** Server name (config key) */ + @JsonProperty("name") String name, + /** Whether this configured server is enabled after session configuration and policy filtering. */ + @JsonProperty("enabled") Boolean enabled, + /** Configuration provenance: user, workspace, plugin, builtin, or managed. */ + @JsonProperty("source") McpServerSource source, + /** Plugin name that provided this server, when source is plugin. */ + @JsonProperty("sourcePlugin") String sourcePlugin, + /** Plugin version that provided this server, when source is plugin. */ + @JsonProperty("sourcePluginVersion") String sourcePluginVersion, + /** Human-readable display name supplied by configuration. */ + @JsonProperty("displayName") String displayName, + /** Observed state from an already materialized matching server. Omitted when no live graph has this configured server; it never determines configuration enablement. */ + @JsonProperty("live") McpConfiguredServerState live +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpConfiguredServerState.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpConfiguredServerState.java new file mode 100644 index 0000000000..0087f2546b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpConfiguredServerState.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Observational state for a matching already materialized MCP server. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record McpConfiguredServerState( + /** Observed connection status. This is not a configuration or readiness guarantee. */ + @JsonProperty("status") McpServerStatus status, + /** Observed connection error, when the materialized server failed. */ + @JsonProperty("error") String error +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpListBuiltinServerNamesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpListBuiltinServerNamesResult.java new file mode 100644 index 0000000000..2a65a679d9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpListBuiltinServerNamesResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Names of the MCP servers the runtime supplies itself. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpListBuiltinServerNamesResult( + /** Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. */ + @JsonProperty("names") List names +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelParams.java new file mode 100644 index 0000000000..0a12a5c26b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Registry search to abandon. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistryCancelParams( + /** Request ID from `mcp.registry.allocateRequestId` that the search uses. */ + @JsonProperty("requestId") Long requestId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelResult.java new file mode 100644 index 0000000000..c7f581f4cc --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Whether the cancel reached a live search. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistryCancelResult( + /** True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. */ + @JsonProperty("canceled") Boolean canceled +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryRequestIdResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryRequestIdResult.java new file mode 100644 index 0000000000..53234b3598 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryRequestIdResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Request id naming a cancellable registry search. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistryRequestIdResult( + /** Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. */ + @JsonProperty("requestId") Long requestId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java new file mode 100644 index 0000000000..11a06de374 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Registry search terms, the credential to search under, and the request id that makes the search cancellable. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistrySearchParams( + /** Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. */ + @JsonProperty("requestId") Long requestId, + /** The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("authInfo") Object authInfo, + /** Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. */ + @JsonProperty("query") String query, + /** Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. */ + @JsonProperty("repository") String repository, + /** Maximum number of servers to return. */ + @JsonProperty("limit") Long limit +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchResult.java new file mode 100644 index 0000000000..2682402d76 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Servers selected from the registry response. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistrySearchResult( + /** The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. */ + @JsonProperty("servers") Object servers +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServer.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServer.java index f2917ced22..9b93d39830 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServer.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServer.java @@ -27,6 +27,8 @@ public record McpServer( @JsonProperty("status") McpServerStatus status, /** Configuration source: user, workspace, plugin, builtin, or managed */ @JsonProperty("source") McpServerSource source, + /** Configured URL for an HTTP/SSE server, regardless of configuration source. Omitted for local and in-memory servers. */ + @JsonProperty("url") String url, /** Plugin name that provided this server, when source is plugin. */ @JsonProperty("sourcePlugin") String sourcePlugin, /** Plugin version that provided this server, when source is plugin. */ @@ -63,6 +65,6 @@ public McpServer( String error, McpServerMetadata serverMetadata ) { - this(name, status, source, sourcePlugin, sourcePluginVersion, displayName, error, serverMetadata, null); + this(name, status, source, null, sourcePlugin, sourcePluginVersion, displayName, error, serverMetadata, null); } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServerSource.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServerSource.java index 72b1503d59..0902ef8812 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServerSource.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpServerSource.java @@ -10,7 +10,7 @@ import javax.annotation.processing.Generated; /** - * Configuration source: user, workspace, plugin, builtin, or managed + * Configuration source: user, workspace, plugin, builtin, managed, or account * * @since 1.0.0 */ @@ -25,7 +25,9 @@ public enum McpServerSource { /** The {@code builtin} variant. */ BUILTIN("builtin"), /** The {@code managed} variant. */ - MANAGED("managed"); + MANAGED("managed"), + /** The {@code account} variant. */ + ACCOUNT("account"); private final String value; McpServerSource(String value) { this.value = value; } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsParams.java new file mode 100644 index 0000000000..bb435663bf --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The session tool filters that decide whether the session still has a shell to run `gh` with. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpShouldExcludeGitHubToolsParams( + /** The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. */ + @JsonProperty("availableTools") List availableTools, + /** The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. */ + @JsonProperty("excludedTools") List excludedTools, + /** How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. */ + @JsonProperty("toolFilterPrecedence") OptionsUpdateToolFilterPrecedence toolFilterPrecedence +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsResult.java new file mode 100644 index 0000000000..05f92ab309 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpShouldExcludeGitHubToolsResult( + /** True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. */ + @JsonProperty("excludeGhReplaceableTools") Boolean excludeGhReplaceableTools +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/Model.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/Model.java index 81ffc46a36..63fbd2937a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/Model.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/Model.java @@ -31,6 +31,8 @@ public record Model( @JsonProperty("capabilities") ModelCapabilities capabilities, /** Provider-supplied model metadata. Keys and JSON-compatible values are preserved unchanged. This is factual metadata published by the model provider; it carries no picker or UX semantics. */ @JsonProperty("metadata") Map metadata, + /** Model vendor as the Copilot API reports it, for example "Anthropic" or "Azure OpenAI". Open vocabulary, passed through unchanged. It can name the vendor that serves the model instead of the one that built it, or a label that is not a vendor, such as "Experimental". Absent when the Copilot API reports no vendor. */ + @JsonProperty("vendor") String vendor, /** Policy state (if applicable) */ @JsonProperty("policy") ModelPolicy policy, /** Billing information */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ModelClearStartupSeedResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ModelClearStartupSeedResult.java new file mode 100644 index 0000000000..d905811186 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ModelClearStartupSeedResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Data type {@code ModelClearStartupSeedResult}. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ModelClearStartupSeedResult( + @JsonProperty("cleared") Boolean cleared +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PendingExternalToolRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PendingExternalToolRequest.java new file mode 100644 index 0000000000..6529827e05 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PendingExternalToolRequest.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * External tool call of the session or one of its sub-agents that is still waiting for session.tools.handlePendingToolCall. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record PendingExternalToolRequest( + /** Request ID to pass to session.tools.handlePendingToolCall */ + @JsonProperty("requestId") String requestId, + /** Tool call ID assigned to this external tool invocation */ + @JsonProperty("toolCallId") String toolCallId, + /** Name of the external tool to invoke */ + @JsonProperty("toolName") String toolName, + /** Arguments to pass to the external tool */ + @JsonProperty("arguments") Object arguments, + /** Stable identity of the provider that offered the tool, for hosts that route extension-owned tools by provider */ + @JsonProperty("providerId") String providerId, + /** Sub-agent instance identifier (the envelope agentId of its events) of the agent that issued the call; absent for calls issued by the root agent */ + @JsonProperty("agentId") String agentId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java index e4c502116d..990349ebaf 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java @@ -24,6 +24,10 @@ public record PermissionRecoveryData( /** Stable identifier shared by every transition in this recovery episode */ @JsonProperty("episodeId") String episodeId, + /** Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Current lifecycle state of the recovery episode */ @JsonProperty("status") PermissionRecoveryStatus status, /** Policy selected from the current client's response capability; mode or client changes may update it during recovery */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyParams.java new file mode 100644 index 0000000000..65a15a044e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The verbatim managed `permissions` slice to interpret. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PermissionsEvaluateManagedPolicyParams( + /** The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. */ + @JsonProperty("permissions") Object permissions +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyResult.java new file mode 100644 index 0000000000..2690dad76f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The policy questions a host asks before granting elevated permissions. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PermissionsEvaluateManagedPolicyResult( + /** True when managed policy forbids bypass-permissions mode, so allow-all style flags must not take effect. */ + @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, + /** True when a managed policy exists but this build could not determine its meaning. Hosts fail closed on it rather than assuming permission was granted. */ + @JsonProperty("policyUndetermined") Boolean policyUndetermined, + /** True when the managed layer supplies permission rules that the session must enforce. */ + @JsonProperty("permissionRulesActive") Boolean permissionRulesActive +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsFolderTrustCheckTrustParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsFolderTrustCheckTrustParams.java new file mode 100644 index 0000000000..5fadba2eec --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsFolderTrustCheckTrustParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PermissionsFolderTrustCheckTrustParams( + /** Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. */ + @JsonProperty("path") String path, + /** Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. */ + @JsonProperty("configDir") String configDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedParams.java new file mode 100644 index 0000000000..eff9c61d51 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A complete JSON snapshot to write under the runtime's per-path file lock. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PersistenceWriteRawJsonLockedParams( + /** Absolute path of the file to replace. Parent directories are created when missing. */ + @JsonProperty("path") String path, + /** The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. */ + @JsonProperty("dataJson") String dataJson, + /** Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. */ + @JsonProperty("fileHeader") String fileHeader +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedResult.java new file mode 100644 index 0000000000..5f8616d042 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The outcome of a locked snapshot write. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PersistenceWriteRawJsonLockedResult( + /** Whether the file now holds the requested contents. */ + @JsonProperty("success") Boolean success, + /** Why the write failed. Absent when `success` is true. A lock the runtime could not acquire in time reports here rather than raising. */ + @JsonProperty("error") String error +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsage.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsage.java new file mode 100644 index 0000000000..355f7e38f0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsage.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * An authoritative monthly usage reading for the observation's provider, account, and service. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderMonthlyUsage( + /** Availability of monthly consumption. Missing or unavailable usage must never be interpreted as zero. */ + @JsonProperty("state") ProviderMonthlyUsageState state, + /** Unit of consumedQuantity; independent of the parent observation's balance unit. */ + @JsonProperty("unit") ProviderQuotaUnit unit, + /** Identity scope of the reading within its provider and service. */ + @JsonProperty("scope") ProviderMonthlyUsageScope scope, + /** Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. */ + @JsonProperty("consumedQuantity") Double consumedQuantity, + /** Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. */ + @JsonProperty("queriedAt") String queriedAt, + /** Start of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("cycleStart") String cycleStart, + /** End of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("resetOn") String resetOn +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageScope.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageScope.java new file mode 100644 index 0000000000..56d9b4dd38 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageScope.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Identity scope of a monthly usage reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageScope { + /** The {@code user} variant. */ + USER("user"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageScope(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageScope fromValue(String value) { + for (ProviderMonthlyUsageScope v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageScope value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageState.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageState.java new file mode 100644 index 0000000000..7788fbc219 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageState.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Availability of a service's monthly consumption reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageState { + /** The {@code available} variant. */ + AVAILABLE("available"), + /** The {@code no_policy} variant. */ + NO_POLICY("no_policy"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageState fromValue(String value) { + for (ProviderMonthlyUsageState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaAccessState.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaAccessState.java new file mode 100644 index 0000000000..d567cb75b3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaAccessState.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Access policy reported by the quota service. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaAccessState { + /** The {@code allowed} variant. */ + ALLOWED("allowed"), + /** The {@code denied} variant. */ + DENIED("denied"), + /** The {@code not_required} variant. */ + NOT_REQUIRED("not_required"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"); + + private final String value; + ProviderQuotaAccessState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaAccessState fromValue(String value) { + for (ProviderQuotaAccessState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaAccessState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaAcquisitionStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaAcquisitionStatus.java new file mode 100644 index 0000000000..575227472b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaAcquisitionStatus.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Acquisition state, independent of the service's business access/capacity verdict. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaAcquisitionStatus { + /** The {@code succeeded} variant. */ + SUCCEEDED("succeeded"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"), + /** The {@code failed} variant. */ + FAILED("failed"); + + private final String value; + ProviderQuotaAcquisitionStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaAcquisitionStatus fromValue(String value) { + for (ProviderQuotaAcquisitionStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaAcquisitionStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaBudgetMetadata.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaBudgetMetadata.java new file mode 100644 index 0000000000..2697dbdf48 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaBudgetMetadata.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Authoritative budget measurements and policy metadata, independent of provider. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderQuotaBudgetMetadata( + /** Whether the budget has unlimited entitlement. */ + @JsonProperty("unlimited") Boolean unlimited, + /** Exact budget entitlement, retaining incumbent fractional-unit compatibility. */ + @JsonProperty("entitlement") Double entitlement, + /** Exact measured consumption in the budget's unit. */ + @JsonProperty("consumed") Double consumed, + /** Service-reported remaining percentage for authoritative budget presentation. */ + @JsonProperty("remainingPercentage") Double remainingPercentage, + /** Whether service policy allows continued usage after exhaustion. */ + @JsonProperty("usageAllowedWhenExhausted") Boolean usageAllowedWhenExhausted, + /** Usage beyond entitlement, in the budget's unit. */ + @JsonProperty("overage") Double overage, + /** Whether additional usage is allowed when the budget is exhausted. */ + @JsonProperty("overageAllowedWhenExhausted") Boolean overageAllowedWhenExhausted, + /** Reset instant in epoch milliseconds when this budget actually defines a window. */ + @JsonProperty("resetAtEpochMs") Double resetAtEpochMs, + /** Whether the reset instant is an estimate. */ + @JsonProperty("resetEstimated") Boolean resetEstimated, + /** Whether this budget uses token-based billing. */ + @JsonProperty("tokenBasedBilling") Boolean tokenBasedBilling, + /** Optional additional-usage budget cap. */ + @JsonProperty("overageLimit") Double overageLimit +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaCapacityState.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaCapacityState.java new file mode 100644 index 0000000000..45e9bf6a98 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaCapacityState.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Capacity is independent of whether a numeric balance was supplied. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaCapacityState { + /** The {@code available} variant. */ + AVAILABLE("available"), + /** The {@code exhausted} variant. */ + EXHAUSTED("exhausted"), + /** The {@code unlimited} variant. */ + UNLIMITED("unlimited"), + /** The {@code not_required} variant. */ + NOT_REQUIRED("not_required"), + /** The {@code not_applicable} variant. */ + NOT_APPLICABLE("not_applicable"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"); + + private final String value; + ProviderQuotaCapacityState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaCapacityState fromValue(String value) { + for (ProviderQuotaCapacityState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaCapacityState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaObservationKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaObservationKind.java new file mode 100644 index 0000000000..ca1406ed70 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaObservationKind.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Timing and purpose of a provider quota observation. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaObservationKind { + /** The {@code account_snapshot} variant. */ + ACCOUNT_SNAPSHOT("account_snapshot"), + /** The {@code admission_state} variant. */ + ADMISSION_STATE("admission_state"); + + private final String value; + ProviderQuotaObservationKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaObservationKind fromValue(String value) { + for (ProviderQuotaObservationKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaObservationKind value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaQuantityKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaQuantityKind.java new file mode 100644 index 0000000000..1282854ba8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaQuantityKind.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Interpretation permitted for independently reported quantities. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaQuantityKind { + /** The {@code authoritative_budget} variant. */ + AUTHORITATIVE_BUDGET("authoritative_budget"), + /** The {@code advisory_balance} variant. */ + ADVISORY_BALANCE("advisory_balance"), + /** The {@code none} variant. */ + NONE("none"); + + private final String value; + ProviderQuotaQuantityKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaQuantityKind fromValue(String value) { + for (ProviderQuotaQuantityKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaQuantityKind value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaState.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaState.java new file mode 100644 index 0000000000..5473712f9c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaState.java @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * An account quota reading. Absence of a quantity is unknown, never zero. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderQuotaState( + /** Provider/account whose service reported this state. */ + @JsonProperty("provider") ModelProviderRef provider, + /** Service-owned quota identifier within this provider. */ + @JsonProperty("quotaId") String quotaId, + /** Unit of entitledQuantity and availableQuantity. */ + @JsonProperty("unit") ProviderQuotaUnit unit, + /** Whether the service permits access, independently of balance. */ + @JsonProperty("accessState") ProviderQuotaAccessState accessState, + /** Service capacity state; missing quantities do not imply exhaustion. */ + @JsonProperty("capacityState") ProviderQuotaCapacityState capacityState, + /** Whether this is a GET account reading or a pre-response admission observation. Observations are never merged across kinds. */ + @JsonProperty("observationKind") ProviderQuotaObservationKind observationKind, + /** Whether quantities are authoritative budget measurements, advisory balances, or absent. Only authoritative budgets support percentage presentation. */ + @JsonProperty("quantityKind") ProviderQuotaQuantityKind quantityKind, + /** Acquisition outcome. Unavailable/failed readings have no service verdict; access/capacity unavailable are compatibility placeholders only. */ + @JsonProperty("acquisitionStatus") ProviderQuotaAcquisitionStatus acquisitionStatus, + /** When the runtime observed this reading, not a charge timestamp or guarantee that consumption has settled. */ + @JsonProperty("observedAt") String observedAt, + /** HTTP status from acquisition, when available. */ + @JsonProperty("httpStatus") Long httpStatus, + /** Service error code or client acquisition category, separate from the business-state reason. */ + @JsonProperty("acquisitionError") String acquisitionError, + /** Optional metadata for an authoritative budget. Advisory balances and admission-only observations do not populate this. */ + @JsonProperty("budgetMetadata") ProviderQuotaBudgetMetadata budgetMetadata, + /** Service-reported monthly consumption, independent of quota balances and per-call or session cost. Omitted when the service does not report monthly usage. */ + @JsonProperty("monthlyUsage") ProviderMonthlyUsage monthlyUsage, + /** Key for the backwards-compatible snapshots projection, when the authoritative budget supports that contract. */ + @JsonProperty("compatibilityKey") String compatibilityKey, + /** Explicit service admission flag, when reported. */ + @JsonProperty("hasQuota") Boolean hasQuota, + /** Independently reported signed 64-bit entitlement. -1 is an unlimited sentinel, not a capacity-state rewrite; omission and null are preserved. */ + @JsonProperty("entitledQuantity") Long entitledQuantity, + /** Independently reported signed 64-bit available quantity. Zero does not override the service access/capacity verdict; omission and null are preserved. */ + @JsonProperty("availableQuantity") Long availableQuantity, + /** Service-reported explanation for the state. */ + @JsonProperty("reason") String reason, + /** Service-reported quota source. */ + @JsonProperty("source") String source, + /** Service name owning this reading. */ + @JsonProperty("service") String service +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaUnit.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaUnit.java new file mode 100644 index 0000000000..9c9e7f3d3e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaUnit.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Units explicitly reported by a quota provider. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderQuotaUnit { + /** The {@code ai_credits} variant. */ + AI_CREDITS("ai_credits"), + /** The {@code requests} variant. */ + REQUESTS("requests"), + /** The {@code tokens} variant. */ + TOKENS("tokens"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderQuotaUnit(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderQuotaUnit fromValue(String value) { + for (ProviderQuotaUnit v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderQuotaUnit value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/QuotaWarningProjection.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/QuotaWarningProjection.java new file mode 100644 index 0000000000..dad4961084 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/QuotaWarningProjection.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * A pending session quota warning, consumed once by takeWarnings. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record QuotaWarningProjection( + /** Existing warning category. */ + @JsonProperty("warningType") String warningType, + /** User-facing warning text. */ + @JsonProperty("message") String message, + /** Related account or upgrade link. */ + @JsonProperty("url") String url +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java index 50f6256352..2da0b13624 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java @@ -25,7 +25,9 @@ public enum RemediationAction { /** The {@code review_sandbox_policy} variant. */ REVIEW_SANDBOX_POLICY("review_sandbox_policy"), /** The {@code allow_sandbox_outbound} variant. */ - ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"); + ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"), + /** The {@code rewind_conversation} variant. */ + REWIND_CONVERSATION("rewind_conversation"); private final String value; RemediationAction(String value) { this.value = value; } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditParams.java new file mode 100644 index 0000000000..c871a3aed7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditParams.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One atomic edit of an allowed top-level repository setting. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsEditParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Shared or local repository settings file. */ + @JsonProperty("scope") RepoSettingsEditScope scope, + /** One canonical top-level repository setting that the allowlist permits. */ + @JsonProperty("key") String key, + /** Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. */ + @JsonProperty("operation") SettingsEditOperation operation, + /** Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. */ + @JsonProperty("value") Object value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditScope.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditScope.java new file mode 100644 index 0000000000..43b64573d5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditScope.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Which repository settings file to edit. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum RepoSettingsEditScope { + /** The {@code repo} variant. */ + REPO("repo"), + /** The {@code local} variant. */ + LOCAL("local"); + + private final String value; + RepoSettingsEditScope(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static RepoSettingsEditScope fromValue(String value) { + for (RepoSettingsEditScope v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown RepoSettingsEditScope value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawParams.java new file mode 100644 index 0000000000..40d25ea68c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Which repository settings file to read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsReadRawParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ + @JsonProperty("scope") String scope +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawResult.java new file mode 100644 index 0000000000..65d5884033 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Parsed repository settings without normalization or layering. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsReadRawResult( + /** Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. */ + @JsonProperty("config") Object config, + /** True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. */ + @JsonProperty("invalid") Boolean invalid +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteAllParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteAllParams.java new file mode 100644 index 0000000000..8b94ff9be4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteAllParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The complete set of repository-overridable settings to store. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsWriteAllParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ + @JsonProperty("scope") String scope, + /** Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteKeyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteKeyParams.java new file mode 100644 index 0000000000..24bc205bc3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteKeyParams.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One key to write or remove in a repository settings file. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsWriteKeyParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ + @JsonProperty("scope") String scope, + /** Canonical top-level key permitted by the repository settings allowlist. */ + @JsonProperty("key") String key, + /** Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. */ + @JsonProperty("value") Object value, + /** True to remove the key instead of writing it. */ + @JsonProperty("delete") Boolean delete +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCheckEnforcementCommandParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCheckEnforcementCommandParams.java new file mode 100644 index 0000000000..b7401231f7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCheckEnforcementCommandParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * One slash command, as typed, to test against the enforcement-block allowlist. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxCheckEnforcementCommandParams( + /** The command name as the user typed it, with or without its leading slash. */ + @JsonProperty("commandName") String commandName, + /** The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. */ + @JsonProperty("args") List args +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCredentialSuggestion.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCredentialSuggestion.java new file mode 100644 index 0000000000..927dcdf5e9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCredentialSuggestion.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SandboxCredentialSuggestion( + /** Environment variable name. The secret value is never returned. */ + @JsonProperty("name") String name, + /** HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. */ + @JsonProperty("suggestedInjectHosts") List suggestedInjectHosts +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxDocsUrlResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxDocsUrlResult.java new file mode 100644 index 0000000000..bb2ed5c1a2 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxDocsUrlResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The documentation URL a host cites when it declines or downgrades a sandbox setting. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxDocsUrlResult( + /** Documentation URL describing the sandbox and the settings that control it. */ + @JsonProperty("url") String url +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxEffectiveForOptionalResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxEffectiveForOptionalResult.java new file mode 100644 index 0000000000..2336d4f195 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxEffectiveForOptionalResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The sandbox a named feature actually launches under. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxEffectiveForOptionalResult( + /** The effective sandbox config for the requested feature, or a disabled sandbox when the feature is routed out of it. */ + @JsonProperty("sandboxJson") Object sandboxJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesParams.java new file mode 100644 index 0000000000..663040c87e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * A batch of file-picker candidates to check against a prepared policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxFilterPickerCandidatesParams( + /** The candidates to check, in the order the answers are returned. */ + @JsonProperty("candidates") List candidates, + /** The session's working directory, matching the one the policy was prepared from. */ + @JsonProperty("cwd") String cwd, + /** The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. */ + @JsonProperty("sandbox") Object sandbox +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesResult.java new file mode 100644 index 0000000000..cbf29a25f3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Per-candidate allow decisions, positionally aligned with the request. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxFilterPickerCandidatesResult( + /** One decision per candidate, in the same order. Always the same length as the request's `candidates`. */ + @JsonProperty("allowed") List allowed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxGetUnsupportedStartupNoticeParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxGetUnsupportedStartupNoticeParams.java new file mode 100644 index 0000000000..c082b52e7d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxGetUnsupportedStartupNoticeParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed sandbox policy in force, which selects which remedy the notice offers. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxGetUnsupportedStartupNoticeParams( + /** The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. */ + @JsonProperty("managedSandbox") Object managedSandbox, + /** True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. */ + @JsonProperty("enabledByUndeterminedPolicy") Boolean enabledByUndeterminedPolicy +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxHostCapability.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxHostCapability.java index e3efc94513..2c4925f402 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxHostCapability.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxHostCapability.java @@ -21,7 +21,7 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record SandboxHostCapability( - /** The policy feature, as an extensible string: ignore names you do not recognize. Known values: `network` (sandboxed commands can reach the network; on Linux this needs the tooling for Bubblewrap's private network namespace, such as slirp4netns), `network_filtering` (host rules and the sandbox proxy; on Linux this needs the same tooling as `network`; on Windows it needs Process Security Environment 1.1 host-loopback support, and a policy that uses it must also set `network.allowLocalNetwork`), `denied_paths` (native enforcement of `filesystem.deniedPaths`), `shell` (shell commands inside the sandbox), and `filesystem_enumeration` (enumerate-only filesystem grants; on Windows this needs Process Security Environment 1.1 filesystem enumeration support, and without it sandboxed PowerShell still runs but cannot resolve its current location; other platforms always report it). */ + /** The policy feature, as an extensible string: ignore names you do not recognize. Known values: `network` (sandboxed commands can reach the network; on Linux this needs the tooling for Bubblewrap's private network namespace, such as slirp4netns), `network_filtering` (host rules and the sandbox proxy; on Linux this needs the same tooling as `network`; on Windows it needs Process Security Environment 1.1 host-loopback support or MXC's PSEC 1.0-only proxy-loopback compatibility capability, and a policy that uses it must also set `network.allowLocalNetwork`; compatibility applies only to an explicit identity-less runtime proxy, not general host-loopback access, and other policy restrictions still apply), `denied_paths` (native enforcement of `filesystem.deniedPaths`), `shell` (shell commands inside the sandbox), and `filesystem_enumeration` (enumerate-only filesystem grants; on Windows this needs Process Security Environment 1.1 filesystem enumeration support, and without it sandboxed PowerShell still runs but cannot resolve its current location; other platforms always report it). */ @JsonProperty("name") String name, /** Whether this host can run the feature. */ @JsonProperty("supported") Boolean supported, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPickerCandidate.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPickerCandidate.java new file mode 100644 index 0000000000..f3c7712a82 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPickerCandidate.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One file-picker suggestion offered up for the sandbox filesystem check. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxPickerCandidate( + /** Absolute path the suggestion would attach. */ + @JsonProperty("path") String path, + /** Whether the suggestion is a directory. A directory the policy does not itself allow may still be needed as a waypoint to an allowed subtree. */ + @JsonProperty("isDirectory") Boolean isDirectory +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyParams.java new file mode 100644 index 0000000000..2895a57e73 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The working directory and sandbox settings to build a file-picker policy from. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxPreparePickerPolicyParams( + /** The session's working directory. Git discovery and grant canonicalization are resolved against it. */ + @JsonProperty("cwd") String cwd, + /** The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. */ + @JsonProperty("sandbox") Object sandbox +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyResult.java new file mode 100644 index 0000000000..07cae03587 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The prepared file-picker policy, or none when the sandbox is disabled. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxPreparePickerPolicyResult( + /** The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the sandbox is disabled or absent, in which case filtering keeps every candidate. */ + @JsonProperty("sandboxJson") Object sandboxJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxyCaCheckRelevanceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxyCaCheckRelevanceParams.java new file mode 100644 index 0000000000..6d66db0a30 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxyCaCheckRelevanceParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SandboxProxyCaCheckRelevanceParams( + /** The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. */ + @JsonProperty("sandboxConfig") SandboxConfig sandboxConfig +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretGetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretGetResult.java new file mode 100644 index 0000000000..5afa3f89d3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretGetResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The stored sandbox proxy password, if one is present. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretGetResult( + /** The stored password. Absent when no entry exists in either the keychain or the on-disk fallback store. */ + @JsonProperty("value") String value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretLocation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretLocation.java new file mode 100644 index 0000000000..d72162ee2e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretLocation.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Where this runtime keeps the sandbox proxy password. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretLocation( + /** Absolute path of the credential store holding the sandbox proxy password. The proxy password belongs to no MCP server, so it is kept in its own directory rather than in the MCP secret store. */ + @JsonProperty("configDir") String configDir, + /** Identifier of the proxy password entry within that store. Derived from the configuration directory, so two Copilot homes on one machine never share an entry. Use it to recognize a `${secret:…}` reference in stored settings as this runtime's own proxy password. */ + @JsonProperty("secretId") String secretId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveParams.java new file mode 100644 index 0000000000..610fb09681 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The sandbox proxy password to store. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretSaveParams( + /** The password to store for the sandbox proxy. */ + @JsonProperty("value") String value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveResult.java new file mode 100644 index 0000000000..543b38083f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Where the sandbox proxy password was stored. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretSaveResult( + /** Whether the OS keychain accepted the value. False means it was written to the on-disk fallback store instead, which is still readable by `sandbox.proxySecret.get`. */ + @JsonProperty("storedInKeychain") Boolean storedInKeychain +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigParams.java new file mode 100644 index 0000000000..738642fa05 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The user's sandbox settings and the managed sandbox floor to raise them to. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxResolveFlooredConfigParams( + /** The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. */ + @JsonProperty("userSandbox") Object userSandbox, + /** The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. */ + @JsonProperty("managedSandbox") Object managedSandbox +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigResult.java new file mode 100644 index 0000000000..043eaaead9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The user's sandbox settings raised to the managed floor. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxResolveFlooredConfigResult( + /** The floored sandbox config, normalized through the declared sandbox shape so only declared fields in a fixed order are present. */ + @JsonProperty("sandboxJson") Object sandboxJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveForOptionalParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveForOptionalParams.java new file mode 100644 index 0000000000..9a523b274e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveForOptionalParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A sandbox config and the per-feature routing flag to resolve it for. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxResolveForOptionalParams( + /** The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. */ + @JsonProperty("sandbox") Object sandbox, + /** The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. */ + @JsonProperty("routingFlag") String routingFlag +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxSettingsApplyDefaultsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxSettingsApplyDefaultsParams.java new file mode 100644 index 0000000000..4b129d0d41 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxSettingsApplyDefaultsParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The stored sandbox settings to resolve against the defaults. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxSettingsApplyDefaultsParams( + /** The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("stored") Object stored +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxUnsupportedStartupNoticeResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxUnsupportedStartupNoticeResult.java new file mode 100644 index 0000000000..2d31660a33 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxUnsupportedStartupNoticeResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The startup warning, absent when the machine can run a sandbox. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxUnsupportedStartupNoticeResult( + /** The user-facing warning, carrying the platform remedy and the recovery the policy in force actually allows. Absent when this machine supports a sandbox, so a host can call unconditionally and print only what it gets. */ + @JsonProperty("notice") String notice +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java index 0adbf18092..8c25672e33 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java @@ -28,7 +28,7 @@ public final class ServerAccountApi { } /** - * Optional opaque account selection or compatibility GitHub token used to look up quota. + * Gets Copilot quota usage for the current or opaquely selected authenticated user. *

* Invokes the method with no params, applying the runtime defaults. * @@ -41,7 +41,7 @@ public CompletableFuture getQuota() { } /** - * Optional opaque account selection or compatibility GitHub token used to look up quota. + * Gets Copilot quota usage for the current or opaquely selected authenticated user. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -52,7 +52,7 @@ public CompletableFuture getQuota(AccountGetQuotaParams p } /** - * Current authentication state + * Gets the currently active authentication credentials from the global auth manager. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -63,7 +63,7 @@ public CompletableFuture getCurrentAuth() { } /** - * List of all authenticated users + * Gets all authenticated users available for account switching. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -74,7 +74,7 @@ public CompletableFuture> getAllUsers() { } /** - * Credentials to validate and store. Omit login to resolve the authenticated user from the token. + * Validates and stores authentication credentials. When login is omitted, resolves the authenticated user from the token before persistence. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -85,7 +85,7 @@ public CompletableFuture login(AccountLoginParams params) { } /** - * User to log out + * Removes user authentication from keychain and persisted state. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -95,4 +95,48 @@ public CompletableFuture logout(AccountLogoutParams params) return caller.invoke("account.logout", params, AccountLogoutResult.class); } + /** + * Renders the sign-in banner and the one-line account description the runtime uses for an authentication identity. The runtime words these in several places for its own callers, so a host that announces a sign-in or an account switch should render them from here rather than composing its own, which would let the two spellings drift apart. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture describeAuthInfo(AccountDescribeAuthInfoParams params) { + return caller.invoke("account.describeAuthInfo", params, AccountDescribeAuthInfoResult.class); + } + + /** + * Reports whether the supplied identity can create gists. Gists are unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed Users on github.com, so a host that offers gist actions should hide or disable them when this reports no support. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getGistSupport(AccountGetGistSupportParams params) { + return caller.invoke("account.getGistSupport", params, AccountGetGistSupportResult.class); + } + + /** + * Resolves a path on the identity's GitHub host into an absolute URL, so a host can link to settings or documentation on the enterprise instance the user is signed in to rather than to github.com. Falls back to the public host when no identity is supplied. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getWebUrl(AccountGetWebUrlParams params) { + return caller.invoke("account.getWebUrl", params, AccountGetWebUrlResult.class); + } + + /** + * Names the environment variable supplying a classic personal access token, if one is set. A classic token cannot be upgraded in place, so a host that finds one should tell the user which variable to unset rather than starting an interactive sign-in that the variable would override. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getTokenEnvVar() { + return caller.invoke("account.getTokenEnvVar", java.util.Map.of(), AccountGetTokenEnvVarResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentRegistryApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentRegistryApi.java index f398fb2dcb..a96ce680d7 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentRegistryApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentRegistryApi.java @@ -27,7 +27,7 @@ public final class ServerAgentRegistryApi { } /** - * Inputs to spawn a managed-server child via the controller's spawn delegate. + * Spawns a managed-server child with the supplied configuration and returns a discriminated-union result. The caller (typically the CLI controller) is responsible for attaching to the spawned child and sending any follow-up prompt. When the controller-local spawn gate is closed the server returns JSON-RPC MethodNotFound. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java index 0c621a3624..287c099c93 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -27,7 +28,7 @@ public final class ServerAgentsApi { } /** - * Optional project paths to include in agent discovery. + * Discovers custom agents across user, project, plugin, and remote sources. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +39,20 @@ public CompletableFuture discover(AgentsDiscoverParams par } /** - * Optional project paths to include when enumerating agent discovery directories. + * Discovers custom agents across user, project, plugin, and remote sources. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture discover(AgentsDiscoverRequest request) { + return caller.invoke("agents.discover", Objects.requireNonNull(request, "request"), AgentsDiscoverResult.class); + } + + /** + * Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -48,4 +62,72 @@ public CompletableFuture getDiscoveryPaths(Agents return caller.invoke("agents.getDiscoveryPaths", params, AgentsGetDiscoveryPathsResult.class); } + /** + * Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getDiscoveryPaths(AgentsGetDiscoveryPathsRequest request) { + return caller.invoke("agents.getDiscoveryPaths", Objects.requireNonNull(request, "request"), AgentsGetDiscoveryPathsResult.class); + } + + /** + * Lists the agents this runtime ships, by name. A consumer separating shipped agents from ones the user or a plugin authored should compare against these names rather than against `AgentInfo.source`: an authored agent may carry the `builtin` source while not being one of these, and the runtime treats the two as separate questions. `disableableNames` is the subset a user may turn off, which a client needs to decide whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML definition, which a client needs before asking the runtime to load one. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getBuiltins() { + return caller.invoke("agents.getBuiltins", java.util.Map.of(), AgentsGetBuiltinsResult.class); + } + + /** + * Lists the shipped agents a client should offer right now, filtered by the feature flags it passes. `getBuiltins` names every agent the runtime knows about; some of those are gated, so a client rendering a picker wants this narrower list together with the description to show beside each name. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getAvailableBuiltins(AgentsGetAvailableBuiltinsParams params) { + return caller.invoke("agents.getAvailableBuiltins", params, AgentsGetAvailableBuiltinsResult.class); + } + + /** + * Loads one shipped agent's YAML definition, for a client that needs what the agent declares rather than only its name. `getBuiltins` reports which names have a definition to load: a name outside its `yamlBasedNames` is special-cased in code and has none. The definition crosses as its own JSON rather than as contract-typed fields, because the runtime parses it with the agent schema's tolerant shape and re-typing it here would drop the keys that shape accepts and this one does not. The projected `__nativeCustomAgent` view the runtime derives is included, so a caller reading the declared model and a caller rendering the agent see the same definition. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getBuiltinDefinition(AgentsGetBuiltinDefinitionParams params) { + return caller.invoke("agents.getBuiltinDefinition", params, AgentsGetBuiltinDefinitionResult.class); + } + + /** + * Projects one shipped agent the way a picker lists it, reading only the metadata at the head of the definition file and stopping before the prompt body. `getBuiltinDefinition` answers the whole definition instead, so a client listing every shipped agent should prefer this one: the cost of a listing grows with the number of agents, and the prompt body is the part a listing never shows. The two also differ in shape. This returns the projected custom agent on its own, whereas `getBuiltinDefinition` returns the authored definition with that projection nested under `__nativeCustomAgent`. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getBuiltinListingDefinition(AgentsGetBuiltinListingDefinitionParams params) { + return caller.invoke("agents.getBuiltinListingDefinition", params, AgentsGetBuiltinListingDefinitionResult.class); + } + + /** + * Resolves the model a custom agent asks for against the models actually available, and answers both the model to switch to and the warning a user should see when the agent's preference cannot be met. A custom agent may name several acceptable models in preference order, so the decision is a match rather than a lookup, and an agent whose preference is unavailable is a normal outcome that produces a warning rather than an error. A host must call this rather than pick the first available name itself, because the preference order and the wording of the warning are what keep one installation's agent selection the same as another's. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture customAgentInitialModelDecision(AgentsCustomAgentInitialModelDecisionParams params) { + return caller.invoke("agents.customAgentInitialModelDecision", params, AgentsCustomAgentInitialModelDecisionResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCatalogApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCatalogApi.java index 32e7963e35..f7d7c2fe1b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCatalogApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCatalogApi.java @@ -28,7 +28,7 @@ public final class ServerCatalogApi { } /** - * A bounded catalog search. Both the query length and the result count are capped by the schema so a caller cannot request an unbounded scan. + * Requests a bounded catalog search. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with search available returns inert candidate summaries, each with an opaque single-use handle scoped to this runtime instance; a runtime without it returns the typed search-unavailable result. Public authorities may be searched anonymously, while an authority that requires credentials yields the typed authentication-required result. All returned text, URLs, and package metadata are untrusted external data and can never trigger instructions, tools, or installation. Read-only: nothing is installed, configured, or persisted. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -39,7 +39,7 @@ public CompletableFuture search(CatalogSearchParams params) } /** - * A bounded catalog search. Both the query length and the result count are capped by the schema so a caller cannot request an unbounded scan. + * Requests a bounded catalog search. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with search available returns inert candidate summaries, each with an opaque single-use handle scoped to this runtime instance; a runtime without it returns the typed search-unavailable result. Public authorities may be searched anonymously, while an authority that requires credentials yields the typed authentication-required result. All returned text, URLs, and package metadata are untrusted external data and can never trigger instructions, tools, or installation. Read-only: nothing is installed, configured, or persisted. *

* Accepts the extensible request, including inputs added after the params record. * @@ -52,7 +52,7 @@ public CompletableFuture search(CatalogSearchRequest reques } /** - * Terminates one retained catalog selection group through an opaque reference previously returned by the model-safe search projection. + * Terminates one retained catalog selection group. A selected outcome returns the native host a fresh single-use candidate handle plus the original searchId for a later explicit mcp.planInstall call; non-selected outcomes release the group without producing a planning input. Candidate state, cards, URLs, credentials and private identifiers remain inside the runtime. The model-facing catalog_select tool projects the result separately and never exposes the candidate handle or searchId. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCommandsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCommandsApi.java index efa5317ea4..82c5fad8c4 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCommandsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerCommandsApi.java @@ -27,7 +27,7 @@ public final class ServerCommandsApi { } /** - * Slash commands available in the session, after applying any include/exclude filters. + * Lists the well-known built-in slash commands that work as the first message in a new session (e.g. /plan, /env), without requiring an active session. Commands that depend on session state, authentication, or a synced session are omitted. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerConnectorsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerConnectorsApi.java new file mode 100644 index 0000000000..5b74d83721 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerConnectorsApi.java @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code connectors} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerConnectorsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerConnectorsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Returns feature availability. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getCapabilities() { + return caller.invoke("connectors.getCapabilities", java.util.Map.of(), ConnectorsGetCapabilitiesResult.class); + } + + /** + * Returns eligible accounts. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getAccounts() { + return caller.invoke("connectors.getAccounts", java.util.Map.of(), ConnectorsGetAccountsResult.class); + } + + /** + * Lists entries for the selected account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture list(ConnectorsListParams params) { + return caller.invoke("connectors.list", params, ConnectorsListResult.class); + } + + /** + * Refreshes entries for the selected account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture refresh(ConnectorsRefreshParams params) { + return caller.invoke("connectors.refresh", params, ConnectorsRefreshResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerEnvironmentsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerEnvironmentsApi.java index 9d52f2f1ea..a8220ef6fc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerEnvironmentsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerEnvironmentsApi.java @@ -27,7 +27,7 @@ public final class ServerEnvironmentsApi { } /** - * Optional discovery filters supported by GitHub Mission Control. + * Lists GitHub Mission Control environments visible to the authenticated identity. Does not require a running host and excludes host relay credentials. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture list(EnvironmentsListParams par } /** - * Identify a Mission Control environment to retrieve. + * Gets safe discovery information for a GitHub Mission Control environment without requiring a running host. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture get(EnvironmentsGetParams params } /** - * Identify a user-managed Mission Control environment to delete. + * Deletes a user-managed GitHub Mission Control environment. GitHub-managed environments cannot be deleted. Does not stop a running host, which may register again. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerExtensionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerExtensionsApi.java index 7bc74b441f..385fc3bbc2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerExtensionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerExtensionsApi.java @@ -27,7 +27,7 @@ public final class ServerExtensionsApi { } /** - * Extensions discovered from persisted Copilot home state and their effective loading mode. Launch-scoped additional plugins are not included. + * Discovers user and enabled installed-plugin extensions from persisted Copilot home state, including enablement preferences. Launch-scoped additional plugins are not included. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture discover() { } /** - * Source-qualified extension identifiers to persistently enable for future sessions. + * Persistently enables extension IDs for future sessions. Active sessions are unchanged; use session.extensions.enable to update them. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture enable(ExtensionsEnableParams params) { } /** - * Source-qualified extension identifiers to persistently disable for future sessions. + * Persistently disables extension IDs for future sessions. Active sessions are unchanged; use session.extensions.disable to update them. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java new file mode 100644 index 0000000000..b2f3444b0a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code featureFlags} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerFeatureFlagsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerFeatureFlagsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Resolves named gates against this installation's cached online-experiment assignment, for the account the runtime is already authenticated as. Unlike `featureFlags.resolve`, which layers static availability with the populations supplied, this reads the experiment assignment the runtime cached for its own current authentication, so a launch can honor a rollout before any session exists. The account is never taken from the request: naming one would read another account's cached assignments. The cached assignment answers immediately and any network refresh happens behind it, so this call does not wait on the network. Not available to an extension, which cannot carry the user's consent to read their assignment. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture> resolveStartupGates(FeatureFlagsResolveStartupGatesParams params) { + return caller.invoke("featureFlags.resolveStartupGates", params, RpcMapper.INSTANCE.getTypeFactory().constructMapType(Map.class, String.class, Boolean.class)); + } + + /** + * Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture listMetadata() { + return caller.invoke("featureFlags.listMetadata", java.util.Map.of(), FeatureFlagsMetadataResult.class); + } + + /** + * Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture> resolve(FeatureFlagsResolveParams params) { + return caller.invoke("featureFlags.resolve", params, RpcMapper.INSTANCE.getTypeFactory().constructMapType(Map.class, String.class, Boolean.class)); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitApi.java new file mode 100644 index 0000000000..da512566d0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitApi.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code git} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerGitApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerGitApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Reads the remote that the branch checked out in a working tree tracks, as `branch..remote` configures it. Reports `origin` rather than failing whenever there is no tracking configuration to read — on a detached HEAD, on a branch with no upstream, or when git itself fails — because a caller asking which remote to talk to needs an answer it can act on, not an error. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture currentBranchRemote(GitCurrentBranchRemoteParams params) { + return caller.invoke("git.currentBranchRemote", params, GitCurrentBranchRemoteResult.class); + } + + /** + * Collects the repository context of a working directory in one call: working tree root, repository identifier and host, current branch, and the HEAD and base commits. Every repository field is omitted when the path is not inside a git working tree, and the requested path is echoed back as `cwd`. The answer is the same `SessionWorkingDirectoryContext` that `session.metadata.recordContextChange` accepts, so a caller polling for a context change can forward the result unchanged. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to derive session context from a directory itself. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture workingDirectoryContext(GitWorkingDirectoryContextParams params) { + return caller.invoke("git.workingDirectoryContext", params, SessionWorkingDirectoryContext.class); + } + + /** + * Lists the GitHub repositories a working tree's remotes point at, one entry per distinct repository, so a caller can resolve a base and head repository without parsing remote URLs itself. When several remotes name the same repository, only the first is listed, and the entry keeps that remote name. Remotes pointing at no GitHub host are left out, so an empty list means the tree reaches GitHub through no remote. Failing to read the remotes is reported as an error rather than as an empty list, because the two mean different things to a caller. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture reposFromRemotes(GitReposFromRemotesParams params) { + return caller.invoke("git.reposFromRemotes", params, GitReposFromRemotesResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitHubOwnersApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitHubOwnersApi.java new file mode 100644 index 0000000000..175c41400a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitHubOwnersApi.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code gitHubOwners} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerGitHubOwnersApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerGitHubOwnersApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Registers a cancellable owner listing and returns its request id. Separate from `gitHubOwners.list` so the id exists before the listing starts: a caller that abandons the listing the moment it begins would otherwise have nothing to name in `gitHubOwners.cancel`. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture nextRequestId() { + return caller.invoke("gitHubOwners.nextRequestId", java.util.Map.of(), GitHubOwnersRequestIdResult.class); + } + + /** + * Lists the logins the authenticated user may act as — their own account first, then the organizations they belong to — by asking the GitHub API under the supplied credential. No credential travels in the request: `authInfo` selects one the runtime already holds, and the runtime resolves the token and the GitHub host from it. A failure the caller should render arrives as `message`; one it should raise arrives as `throwError`. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture list(GitHubOwnersListParams params) { + return caller.invoke("gitHubOwners.list", params, GitHubOwnersListResult.class); + } + + /** + * Abandons an owner listing started with the given request id. Answers `canceled: true` while a listing with that id is running. Answers `canceled: false` when the id was never registered, was registered but not used, was released after being abandoned, or its listing has ended. Canceling an unused id releases it, and a later `list` with that id is refused. The cancel acts only on owner listings and never reaches another request of the host. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture cancel(GitHubOwnersCancelParams params) { + return caller.invoke("gitHubOwners.cancel", params, GitHubOwnersCancelResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitHubRepositoryApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitHubRepositoryApi.java new file mode 100644 index 0000000000..d3eb8f0bd0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGitHubRepositoryApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code gitHubRepository} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerGitHubRepositoryApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerGitHubRepositoryApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Resolves the GitHub repository that owns a working-tree path by reading the selected git remote configured for it, preferring `origin`. Returns a null `repository` when the path is inside a git working tree but that selected remote does not resolve to a GitHub host. Fails when the path is not inside a git working tree at all, so a caller can tell 'not a repository' apart from 'a repository with no GitHub remote'. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture atPath(GitHubRepositoryAtPathParams params) { + return caller.invoke("gitHubRepository.atPath", params, GitHubRepositoryAtPathResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java new file mode 100644 index 0000000000..2d41182ae0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code globalState} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerGlobalStateApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerGlobalStateApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Reads the host's machine-wide state: which plugins are installed and the one-off flags and timestamps that record what the user has already been shown or migrated. This is the state that outlives a single session and a single workspace, so a host reads it to decide whether to run a first-launch step, offer an onboarding prompt, or skip one it has already completed. The stored credentials are deliberately not part of this result; a caller that needs an authenticated identity asks the account methods for it instead. Reading is non-destructive and every field is optional, because a fresh install has recorded nothing yet. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture load() { + return caller.invoke("globalState.load", java.util.Map.of(), GlobalStateLoadResult.class); + } + + /** + * Reads the host's machine-wide state exactly as `globalState.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the state read matches the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `globalState.load`. The stored credentials are omitted here for the same reason they are omitted from `globalState.load`: a caller that needs an authenticated identity asks the account methods instead, so pointing this at another directory cannot be used to read the credentials kept in it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadForConfigDir(GlobalStateLoadForConfigDirParams params) { + return caller.invoke("globalState.loadForConfigDir", params, GlobalStateLoadResult.class); + } + + /** + * Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeKey(GlobalStateWriteKeyParams params) { + return caller.invoke("globalState.writeKey", params, Void.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java index b6f69bf7dc..0997c6588f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -27,7 +28,7 @@ public final class ServerHooksApi { } /** - * Optional project paths and host-exclusion behavior for server-scoped hook discovery. + * Discovers hook actions enabled under server-side discovery settings from user, repository, plugin, and managed-policy sources. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -37,4 +38,17 @@ public CompletableFuture discover(HooksDiscoverParams param return caller.invoke("hooks.discover", params, HooksDiscoverResult.class); } + /** + * Discovers hook actions enabled under server-side discovery settings from user, repository, plugin, and managed-policy sources. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture discover(HooksDiscoverRequest request) { + return caller.invoke("hooks.discover", Objects.requireNonNull(request, "request"), HooksDiscoverResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHostApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHostApi.java index 2cb0c99c37..613fc1a318 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHostApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHostApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -27,7 +28,7 @@ public final class ServerHostApi { } /** - * Publishes a resident session attached to the listener's owning connection. + * Publishes an attached resident session for this listener's lifetime without copying it. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +39,18 @@ public CompletableFuture publishSession(HostPublishSes } /** - * One application-owned session handoff, requested by the supervised hosting participant. + * Reads the complete advertised live and dormant session catalog of an existing host owned by this connection. Does not start hosting, subscribe to sessions, or guarantee resumability. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture listSessions(HostListSessionsParams params) { + return caller.invoke("host.listSessions", params, HostListSessionsResult.class); + } + + /** + * Requests app-owned materialization over the owning SDK participant. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +61,7 @@ CompletableFuture createSession(HostCreateSessionParams } /** - * Ends one participation, not the application's session lifetime. + * Releases app ownership retention after AHP detaches. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -60,7 +72,7 @@ CompletableFuture releaseSession(HostReleaseSessionParams params) { } /** - * Starts a supervised AHP host with at least one explicitly selected transport. + * Starts a connection-owned AHP host with explicit localServer and/or githubEnvironment transports as a supervised SDK participant. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -71,7 +83,20 @@ public CompletableFuture start(HostStartParams params) { } /** - * Stops a connection-owned listener and joins its teardown. + * Starts a connection-owned AHP host with explicit localServer and/or githubEnvironment transports as a supervised SDK participant. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture start(HostStartRequest request) { + return caller.invoke("host.start", Objects.requireNonNull(request, "request"), HostStartResult.class); + } + + /** + * Stops a listener owned by this SDK connection and joins its cleanup without deleting sessions. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -82,7 +107,7 @@ public CompletableFuture dispose(HostDisposeParams params) { } /** - * Empty acknowledgement for a completed host lifecycle operation. + * Resolves current authenticated credentials and remote-control policy only for the runtime-owned Mission Control hosting participant. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -93,7 +118,7 @@ CompletableFuture getEnvironmentCredentials() { } /** - * Empty acknowledgement for a completed host lifecycle operation. + * Returns listener settings only to the supervised hosting participant over its SDK connection. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -104,7 +129,7 @@ CompletableFuture getConfiguration() { } /** - * Readiness reported by the supervised hosting participant on its own SDK connection. + * Reports a supervised hosting participant's bound AHP endpoint after its SDK handshake. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionSourceList.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionSourceList.java new file mode 100644 index 0000000000..cddf0f9f88 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionSourceList.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Instruction sources discovered across user, repository, and plugin sources. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ServerInstructionSourceList( + /** All discovered instruction sources */ + @JsonProperty("sources") List sources +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java index 70eb5b0211..55298f8c4a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -27,7 +28,18 @@ public final class ServerInstructionsApi { } /** - * Optional project paths to include in instruction discovery. + * Returns the prompt the `init` command runs to author repository instructions. A host offering its own initialize action sends this text so the instructions it produces match the ones the CLI produces. The text is fixed for a build and depends on no configuration, session or repository. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getInitPrompt() { + return caller.invoke("instructions.getInitPrompt", java.util.Map.of(), InstructionsInitPromptResult.class); + } + + /** + * Discovers instruction sources across user, repository, and plugin sources. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +50,31 @@ public CompletableFuture discover(InstructionsDiscov } /** - * Optional project paths to include when enumerating instruction discovery targets. + * Discovers instruction sources across user, repository, and plugin sources. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture discover(InstructionsDiscoverRequest request) { + return caller.invoke("instructions.discover", Objects.requireNonNull(request, "request"), InstructionsDiscoverResult.class); + } + + /** + * Discovers the instruction sources for one caller-named location and returns them in the order the runtime applies them. `discover` answers for a set of project paths and derives the rest of its scope itself; this one instead takes every argument from the caller — the extra directories to scan and whether to descend into nested instruction files — and honors them as given. It also includes instruction directories from trusted repository settings, matching native repository discovery. Use it when the caller knows its own scope and no session exists to derive that scope from, such as a host reporting how many instruction files a directory contributes before any session starts. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture discoverRepoSources(InstructionsDiscoverRepoSourcesParams params) { + return caller.invoke("instructions.discoverRepoSources", params, ServerInstructionSourceList.class); + } + + /** + * Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -48,4 +84,28 @@ public CompletableFuture getDiscoveryPaths( return caller.invoke("instructions.getDiscoveryPaths", params, InstructionsGetDiscoveryPathsResult.class); } + /** + * Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getDiscoveryPaths(InstructionsGetDiscoveryPathsRequest request) { + return caller.invoke("instructions.getDiscoveryPaths", Objects.requireNonNull(request, "request"), InstructionsGetDiscoveryPathsResult.class); + } + + /** + * Drops the runtime's in-memory cache of discovered custom instructions so the next discovery reads them from disk again. A host calls this after it changes instruction files, or after it trusts a folder whose instructions an earlier discovery skipped, so that a session started afterwards sees the current files instead of a cached earlier answer. The call performs no I/O of its own and removes nothing from disk; it only invalidates, so the cost lands on the next discovery. Returns once the cache is clear, which is what lets a caller order a session start after it. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture clearCache() { + return caller.invoke("instructions.clearCache", java.util.Map.of(), Void.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerLlmInferenceApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerLlmInferenceApi.java index 4b7663f1f3..753eccb9f3 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerLlmInferenceApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerLlmInferenceApi.java @@ -27,7 +27,7 @@ public final class ServerLlmInferenceApi { } /** - * Indicates whether the calling client was registered as the LLM inference provider. + * Registers an SDK client as the LLM inference callback provider. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture setProvider() { } /** - * Response head. + * Delivers the response head (status + headers) for an in-flight request, correlated by the requestId the runtime supplied in httpRequestStart. Must be called exactly once per request before any httpResponseChunk frames. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture httpResponseStart( } /** - * A response body chunk or terminal error. + * Delivers a body byte range (or a terminal transport error) for an in-flight response, correlated by requestId. Set `end` true on the last chunk. When `error` is set the response terminates with a transport-level failure and the runtime raises an APIConnectionError. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java index 4f9cd612bf..666a1052e0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java @@ -21,13 +21,127 @@ public final class ServerManagedSettingsApi { private final RpcCaller caller; + /** API methods for the {@code managedSettings.permissions} sub-namespace. */ + public final ServerManagedSettingsPermissionsApi permissions; + /** @param caller the RPC transport function */ ServerManagedSettingsApi(RpcCaller caller) { this.caller = caller; + this.permissions = new ServerManagedSettingsPermissionsApi(caller); + } + + /** + * Discovers device-managed settings the way the runtime's own device layer does, and reports the sandbox floor and the load outcome alongside the validated document. This differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a document that validates to an empty object is reported as absent rather than as an empty policy, a discovery error does not suppress a document that still validates, and a failure is reported as a flag rather than only as error text. Hosts that compose the device layer into an effective policy use this, because `managedSettings.read` cannot distinguish "no device policy" from "device policy could not be read" and would silently hand the user's own layer the win. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture readDevice() { + return caller.invoke("managedSettings.readDevice", java.util.Map.of(), ManagedSettingsReadDeviceResult.class); + } + + /** + * Retains the supplied managed layers as this runtime process's startup policy and re-applies the result to every live session. Hosts that own their own short-lived process policy use this, so a guarded mutation is checked against the policy the host actually fetched. Retaining is a whole-process replacement rather than a merge, so a host that already resolved a good policy must not retain a partial one over it. The failure flags are honest inputs rather than assumptions: reporting a fetch or load that failed keeps the layers already retained, and the interim fail-closed state, instead of clearing them. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture retainPolicy(ManagedSettingsRetainPolicyParams params) { + return caller.invoke("managedSettings.retainPolicy", params, Void.class); + } + + /** + * Stamps an effective managed policy's individually-controlled entries onto a user settings document, returning the settings a host should actually act on. The managed layer wins on every plugin spec and marketplace name it names, and leaves everything it does not name as the user wrote it. Hosts use this rather than merging the two documents themselves, because the merge is per entry rather than per document and a whole-document overlay would either discard the user's unmanaged entries or let a user entry outrank a managed one. Omitting the managed layer returns the settings unchanged, which is what an unmanaged host wants. Rejects when either document is present but is not a JSON object rather than treating it as absent, since silently dropping a malformed policy hands the user's layer the win on exactly the entries the policy exists to control. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture applyControls(ManagedSettingsApplyControlsParams params) { + return caller.invoke("managedSettings.applyControls", params, ManagedSettingsApplyControlsResult.class); + } + + /** + * Validates the managed settings a client is supplying for a session it is about to open, and returns them reduced to the keys a client is allowed to set. A client-supplied policy is not the same thing as an administrator's: it may only narrow permissions, so this accepts `permissions` and rejects every other key outright rather than ignoring it. Rejecting is the point — a host that silently dropped an unsupported key would report a policy as applied while running without it. Hosts call this before opening the session rather than letting the open fail, so a malformed policy is reported against the request that carried it. The runtime applies the same rule again when the session starts, so this cannot be used to smuggle a wider document past it. An accepted document that sets nothing comes back as an empty object, which is distinct from supplying nothing at all. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture parseClientValue(ManagedSettingsParseClientValueParams params) { + return caller.invoke("managedSettings.parseClientValue", params, ManagedSettingsParseClientValueResult.class); + } + + /** + * Composes the supplied server, device/MDM, device sandbox floor and policy-helper layers into the single effective managed policy a host should enforce, resolving each key across the layers by the runtime's own precedence rules. Hosts that assemble managed layers themselves use this so their precedence matches the runtime's exactly instead of reimplementing it. The composition is not a pure function of its inputs: an advisory sandbox force-on that arrived over the server channel is declined when this host cannot run a sandbox, so the result reflects the runtime host's capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when that happened. Enforced channels (device/MDM and policy helper) are never declined, and a server force-on carrying `failIfUnavailable` is preserved so the session fails loudly instead of quietly running unsandboxed. Rejects when a supplied layer is present but is not a JSON object, rather than treating it as unmanaged, because silently dropping a malformed policy would hand the user's own layer the win on exactly the keys the policy exists to control. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveEffectiveValue(ManagedSettingsResolveEffectiveValueParams params) { + return caller.invoke("managedSettings.resolveEffectiveValue", params, ManagedSettingsResolveEffectiveValueResult.class); + } + + /** + * Decides what a host must do to its bypass-permissions state after a managed-policy resolution lands, given the state already in force and the account now signed in. A host holds two pieces of state — which layer disabled bypass mode, and for a server-delivered disable, the account it was pinned to — and cannot decide the next step from the new policy alone. Three rules make that so, and each one is a control rather than a preference. A device/MDM disable outranks the account, so a later server answer never lifts it. An unknown policy, which is what a failed fetch or a refusal this build cannot enforce yields, preserves whatever is in force instead of reverting to permissive. And a server disable is lifted only when the account it was pinned to is no longer the signed-in one, which is what makes signing in to an unrestricted account recover without a restart while a reconnect on the same restricted account does not. Hosts call this rather than reimplementing it because getting the pinning backwards either strands a disable on an account that never carried one or drops one that still applies. `setDisabledState` is omitted when the host must leave its stored flag untouched, which is distinct from being told to set it to false. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveBypassDisableTransition(ManagedSettingsResolveBypassDisableTransitionParams params) { + return caller.invoke("managedSettings.resolveBypassDisableTransition", params, ManagedSettingsResolveBypassDisableTransitionResult.class); + } + + /** + * Resolves managed (enterprise policy) settings for a host from every layer at once: the account's server-delivered policy, the device/MDM layer, and a platform policy helper. Hosts use this instead of fetching and composing the layers themselves, because the per-layer precedence and the fail-closed rules that apply when a layer cannot be confirmed are the runtime's own and must match the policy a session will later enforce. It does not retain or apply anything to process-global policy state, so a host may call it before any session exists — which is the point, since plugin activation and one-shot commands resolve policy before a session is available to carry it. The returned per-layer outcome flags are load-bearing rather than diagnostic: a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather than logging them, so a host that runs before a log sink exists still sees them. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture ingest(ManagedSettingsIngestParams params) { + return caller.invoke("managedSettings.ingest", params, ManagedSettingsIngestResult.class); + } + + /** + * Resolves the managed (enterprise policy) settings a host must enforce from startup, and judges the account against the enterprise sign-in pin in the same pass. This composes the layers the way `managedSettings.ingest` does and then answers the two questions a host cannot answer for itself: which fail-closed floors apply when a layer could not be confirmed, and whether this credential is allowed to sign in at all. The sign-in verdict is the reason a host must not assemble this itself from `managedSettings.ingest` — a pinned organization is an access control, and a host that composed the layers but skipped the pin would let a developer sign in with a personal or another enterprise's account and escape every control that keys off the signed-in identity. The verdict is computed on every resolution, including one that is not retained, so declining to apply policy never widens access. Set `retainAndApply` to keep the resolved policy as this runtime process's startup policy; leave it false to resolve without side effects. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveStartupPolicy(ManagedSettingsResolveStartupPolicyParams params) { + return caller.invoke("managedSettings.resolveStartupPolicy", params, ManagedSettingsResolveStartupPolicyResult.class); + } + + /** + * Resolves the managed `remoteControl` policy for an account on its own, for a host deciding whether a remote-control session may start. Composes the same layers as `managedSettings.ingest` and returns only that one key, so a host does not have to know which layer won. An absent policy means the account is unmanaged for this capability and the host may proceed; that default is safe only while absence really does mean "no policy", so a service refusal that says an account policy exists which this client is too old to enforce resolves to an explicit disabled policy instead of to absence. A resolution that cannot be completed is rejected rather than answered as absence, for the same reason. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadRemoteControl(ManagedSettingsLoadRemoteControlParams params) { + return caller.invoke("managedSettings.loadRemoteControl", params, ManagedSettingsLoadRemoteControlResult.class); + } + + /** + * Evaluates the device-channel enterprise sign-in pin (MDM plist, registry, or managed-settings file) against a credential, without resolving any server-delivered policy. This is the gate an entry point runs before it branches, and the only one that can refuse a developer's first sign-in: it is local, needs no credential, and a server-delivered pin only ever reaches accounts already inside the organization. It fails closed by construction — a discovery that cannot determine whether a pin exists refuses rather than allows, because a control that fails open under a triggerable condition is not a control. Hosts that also want the server channel should call `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveDeviceForceLoginOrgsGate(ManagedSettingsResolveDeviceForceLoginOrgsGateParams params) { + return caller.invoke("managedSettings.resolveDeviceForceLoginOrgsGate", params, ForceLoginOrgsDecision.class); } /** - * Validated device-managed settings discovered before a session exists. + * Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +152,7 @@ public CompletableFuture read() { } /** - * Invokes {@code managedSettings.clearCache}. + * Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +163,7 @@ public CompletableFuture clearCache() { } /** - * Optional opaque account selection or GitHub token whose managed settings are resolved. + * Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. *

* Invokes the method with no params, applying the runtime defaults. * @@ -62,7 +176,7 @@ public CompletableFuture resolve() { } /** - * Optional opaque account selection or GitHub token whose managed settings are resolved. + * Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -73,7 +187,7 @@ public CompletableFuture resolve(ManagedSettingsRe } /** - * The authoring JSON schema for managed settings recognized by this runtime. + * Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -84,7 +198,7 @@ public CompletableFuture schema() { } /** - * A candidate managed-settings document to validate without applying it. + * Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -95,7 +209,7 @@ public CompletableFuture validate(ManagedSettings } /** - * Candidate managed-settings documents to merge without applying them. + * Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsPermissionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsPermissionsApi.java new file mode 100644 index 0000000000..11526bde65 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsPermissionsApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code managedSettings.permissions} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerManagedSettingsPermissionsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerManagedSettingsPermissionsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture evaluate(ManagedSettingsPermissionsEvaluateParams params) { + return caller.invoke("managedSettings.permissions.evaluate", params, ManagedSettingsPermissionsEvaluateResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java index 9557a2f4ac..c35de551fc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java @@ -24,6 +24,8 @@ public final class ServerMcpApi { /** API methods for the {@code mcp.config} sub-namespace. */ public final ServerMcpConfigApi config; + /** API methods for the {@code mcp.registry} sub-namespace. */ + final ServerMcpRegistryApi registry; /** API methods for the {@code mcp.installations} sub-namespace. */ public final ServerMcpInstallationsApi installations; @@ -31,11 +33,12 @@ public final class ServerMcpApi { ServerMcpApi(RpcCaller caller) { this.caller = caller; this.config = new ServerMcpConfigApi(caller); + this.registry = new ServerMcpRegistryApi(caller); this.installations = new ServerMcpInstallationsApi(caller); } /** - * Optional working directory used as context for MCP server discovery. + * Discovers MCP servers from user, workspace, plugin, and builtin sources. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -46,7 +49,29 @@ public CompletableFuture discover(McpDiscoverParams params) { } /** - * A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. + * Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture listBuiltinServerNames() { + return caller.invoke("mcp.listBuiltinServerNames", java.util.Map.of(), McpListBuiltinServerNamesResult.class); + } + + /** + * Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture shouldExcludeGitHubTools(McpShouldExcludeGitHubToolsParams params) { + return caller.invoke("mcp.shouldExcludeGitHubTools", params, McpShouldExcludeGitHubToolsResult.class); + } + + /** + * Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -57,7 +82,7 @@ public CompletableFuture planInstall(McpPlanInstallParams } /** - * A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. + * Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. *

* Accepts the extensible request, including inputs added after the params record. * @@ -70,7 +95,7 @@ public CompletableFuture planInstall(McpPlanInstallRequest } /** - * Side-effect-free preparation of one original bound remote MCP choice. + * Consumes a bound catalogue plan and retains one exact fully resolved personal remote MCP operation requiring no supplied values or configured secrets. Returns its runtime operation ID and original expiry before any confirmation, activation, writer initialisation or installation effect. Register the original connection, operation and selected-session binding before calling applyInstall. Missing lower owned admission is unavailable, never a raw-config fallback. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -81,7 +106,7 @@ public CompletableFuture prepareInstall(McpPrep } /** - * Applies exactly one previously prepared operation on its original connection. + * Consumes a retained prepared MCP operation once, revalidates its original authority, requests explicit human consent through installations.confirm on the original connection, then revalidates source and applies the sealed transaction. An uncertain result requires original-operation inspection or recovery, never replay. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -92,7 +117,7 @@ public CompletableFuture applyInstall(McpApplyInstallPara } /** - * Read-only preparation of one owned removal under fresh selected-session authority. + * Prepares a read-only removal plan for an exact owned receipt under the selected existing session. Returns the original operation ID before confirmation; neither planning nor abandonment changes configuration or shared OAuth credentials. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -103,7 +128,7 @@ public CompletableFuture planUninstall(McpPlanU } /** - * One-use application of the exact retained removal plan. + * Consumes the original owned-removal plan once and requests fresh exact human confirmation on its original connection. Drift is refused; unrelated manual configuration and shared OAuth credentials are preserved. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpConfigApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpConfigApi.java index 6d3510f515..7271e94e29 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpConfigApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpConfigApi.java @@ -27,7 +27,7 @@ public final class ServerMcpConfigApi { } /** - * User-configured MCP servers, keyed by server name. + * Lists MCP servers from user configuration. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture list() { } /** - * MCP server name and configuration to add to user configuration. + * Adds an MCP server to user configuration. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture add(McpConfigAddParams params) { } /** - * MCP server name and replacement configuration to write to user configuration. + * Updates an MCP server in user configuration. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -60,7 +60,7 @@ public CompletableFuture update(McpConfigUpdateParams params) { } /** - * MCP server name to remove from user configuration. + * Removes an MCP server from user configuration. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -71,7 +71,7 @@ public CompletableFuture remove(McpConfigRemoveParams params) { } /** - * MCP server names to enable for new sessions. + * Enables MCP servers in user configuration for new sessions. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -82,7 +82,7 @@ public CompletableFuture enable(McpConfigEnableParams params) { } /** - * MCP server names to disable for new sessions. + * Disables MCP servers in user configuration for new sessions. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -93,7 +93,7 @@ public CompletableFuture disable(McpConfigDisableParams params) { } /** - * Invokes {@code mcp.config.reload}. + * Drops this runtime process's in-memory MCP server-definition cache so the next MCP config read observes disk. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpInstallationsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpInstallationsApi.java index ec99b766e9..6055d0fd3f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpInstallationsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpInstallationsApi.java @@ -27,7 +27,7 @@ public final class ServerMcpInstallationsApi { } /** - * New-work inventory or recovery request under an explicitly selected existing session. + * Reads receipt-owned MCP inventory for the selected account and host without activating servers or reconstructing missing ownership. Configuration ownership does not prove session-specific usability. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture list(McpInstallationsL } /** - * New-work inventory or recovery request under an explicitly selected existing session. + * Reconciles already-confirmed durable MCP transactions, then inspects owned inventory. Does not replay apply or reconstruct deleted ownership metadata; unresolved or unsafe evidence remains an explicit refusal. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture recover(McpInstallatio } /** - * Existing-operation control. A new session selector is deliberately not accepted. + * Inspects a known operation only on its original connection. Remains available after account or selected-session loss; does not acquire new authority or rebind an operation. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -60,7 +60,7 @@ public CompletableFuture status(McpInstallation } /** - * Existing-operation control. A new session selector is deliberately not accepted. + * Requests cancellation of a known operation on its original connection, including before apply or confirmation. Already-started effects retain their transaction lease and report an honest terminal or recovery outcome. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpRegistryApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpRegistryApi.java new file mode 100644 index 0000000000..26b7b2cc7f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpRegistryApi.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code mcp.registry} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerMcpRegistryApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerMcpRegistryApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture allocateRequestId() { + return caller.invoke("mcp.registry.allocateRequestId", java.util.Map.of(), McpRegistryRequestIdResult.class); + } + + /** + * Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture search(McpRegistrySearchParams params) { + return caller.invoke("mcp.registry.search", params, McpRegistrySearchResult.class); + } + + /** + * Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture cancel(McpRegistryCancelParams params) { + return caller.invoke("mcp.registry.cancel", params, McpRegistryCancelResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerModelsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerModelsApi.java index e4fd3cbc53..491340551d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerModelsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerModelsApi.java @@ -27,7 +27,7 @@ public final class ServerModelsApi { } /** - * Optional opaque account selection or compatibility GitHub token used to list models. + * Lists Copilot models available to the authenticated user. *

* Invokes the method with no params, applying the runtime defaults. * @@ -40,7 +40,7 @@ public CompletableFuture list() { } /** - * Optional opaque account selection or compatibility GitHub token used to list models. + * Lists Copilot models available to the authenticated user. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -51,7 +51,7 @@ public CompletableFuture list(ModelsListParams params) { } /** - * The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. + * Returns the running runtime's complete catalog of well-known built-in model IDs without authentication or network access. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsApi.java new file mode 100644 index 0000000000..7e1c94d468 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsApi.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code permissions} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPermissionsApi { + + private final RpcCaller caller; + + /** API methods for the {@code permissions.locations} sub-namespace. */ + final ServerPermissionsLocationsApi locations; + /** API methods for the {@code permissions.folderTrust} sub-namespace. */ + final ServerPermissionsFolderTrustApi folderTrust; + + /** @param caller the RPC transport function */ + ServerPermissionsApi(RpcCaller caller) { + this.caller = caller; + this.locations = new ServerPermissionsLocationsApi(caller); + this.folderTrust = new ServerPermissionsFolderTrustApi(caller); + } + + /** + * Interprets a verbatim managed `permissions` slice into the three policy questions a host asks before granting elevated permissions: whether bypass-permissions mode is forbidden, whether a policy exists that this build could not determine, and whether the layer supplies permission rules the session must enforce. An absent or empty slice means no managed policy applies. The runtime and its permission service share one policy type, so a new managed permission setting is interpreted in exactly one place; a host that reimplements the reading would silently diverge the first time that set grows. Hosts must fail closed on an undetermined policy rather than treating it as permission granted. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture evaluateManagedPolicy(PermissionsEvaluateManagedPolicyParams params) { + return caller.invoke("permissions.evaluateManagedPolicy", params, PermissionsEvaluateManagedPolicyResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsFolderTrustApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsFolderTrustApi.java new file mode 100644 index 0000000000..f27b5f0ed1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsFolderTrustApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code permissions.folderTrust} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPermissionsFolderTrustApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerPermissionsFolderTrustApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Reports whether a folder is trusted, reading the persisted trusted-folders list directly rather than through a session. Use this from a host that has no session yet, such as a one-shot command deciding whether to honor a checkout's own settings. It differs from the session-scoped check in two ways that matter: it takes the configuration directory to read the list from, instead of inheriting the session's, and it answers only from the persisted list, so trust a user granted for the lifetime of one session is not visible here. A host that has a session should prefer the session-scoped check, which also covers session-only trust. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkTrust(PermissionsFolderTrustCheckTrustParams params) { + return caller.invoke("permissions.folderTrust.checkTrust", params, FolderTrustCheckResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsLocationsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsLocationsApi.java new file mode 100644 index 0000000000..7b23a73b3f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsLocationsApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code permissions.locations} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPermissionsLocationsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerPermissionsLocationsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Drops stored per-location permission grants whose directory no longer exists, and reports which location keys were removed. Runs against the permission store under the runtime's own Copilot home, the same store `session.permissions.locations.resolve` reads. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to prune its own permission store. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture cleanupOrphaned() { + return caller.invoke("permissions.locations.cleanupOrphaned", java.util.Map.of(), LocationPermissionsCleanupResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPersistenceApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPersistenceApi.java new file mode 100644 index 0000000000..a98b036d8a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPersistenceApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code persistence} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPersistenceApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerPersistenceApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Atomically replaces a JSON file's entire contents while holding the runtime's per-path lock. The lock lives in the runtime process, so a host that writes these files itself takes no part in it and can tear a concurrent runtime write; route the write here instead. Unlike a merging write this never reads or parses the existing file, so a previously corrupted snapshot is replaced wholesale rather than failing every later write. Use it only for callers that always persist a complete snapshot. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeRawJsonLocked(PersistenceWriteRawJsonLockedParams params) { + return caller.invoke("persistence.writeRawJsonLocked", params, PersistenceWriteRawJsonLockedResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsApi.java index da5ac6c0e8..4fd1a839b0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsApi.java @@ -34,7 +34,7 @@ public final class ServerPluginsApi { } /** - * Plugins installed in user/global state. + * Lists plugins installed in user/global state. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -45,7 +45,7 @@ public CompletableFuture list() { } /** - * Plugin source and optional working directory for relative-path resolution. + * Installs a plugin from a marketplace, GitHub repo, URL, or local path. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -56,7 +56,7 @@ public CompletableFuture install(PluginsInstallParams para } /** - * Name (or spec) of the plugin to uninstall. + * Uninstalls an installed plugin. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -67,7 +67,7 @@ public CompletableFuture uninstall(PluginsUninstallParams params) { } /** - * Name (or spec) of the plugin to update. + * Updates an installed plugin to its latest published version. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -78,7 +78,7 @@ public CompletableFuture update(PluginsUpdateParams params) } /** - * Result of updating all installed plugins. + * Updates every installed plugin to its latest published version. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -89,7 +89,7 @@ public CompletableFuture updateAll() { } /** - * Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. + * Enables installed plugins for new sessions. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -100,7 +100,7 @@ public CompletableFuture enable(PluginsEnableParams params) { } /** - * Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. + * Disables installed plugins for new sessions. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsBuiltinApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsBuiltinApi.java index 0610fcb28e..b35a77a817 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsBuiltinApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsBuiltinApi.java @@ -27,7 +27,7 @@ public final class ServerPluginsBuiltinApi { } /** - * Trusted built-in plugin directories to use for this runtime process. + * Replaces this server's trusted built-in plugin directories while no sessions are active. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsMarketplacesApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsMarketplacesApi.java index e01bbeeec7..93adce4997 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsMarketplacesApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPluginsMarketplacesApi.java @@ -27,7 +27,7 @@ public final class ServerPluginsMarketplacesApi { } /** - * All registered marketplaces, including built-in defaults. + * Lists all registered marketplaces (defaults + user-added). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture list() { } /** - * Marketplace source and optional working directory for relative-path resolution. + * Registers a new marketplace from a source (owner/repo, URL, or local path). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture add(PluginsMarketplacesAd } /** - * Name of the marketplace to remove and an optional force flag. + * Removes a previously-registered marketplace. When the marketplace has dependent plugins and `force` is not set, the marketplace is left intact and the result lists the dependents so the caller can decide whether to retry with `force=true`. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -60,7 +60,7 @@ public CompletableFuture remove(PluginsMarketpl } /** - * Name of the marketplace whose plugin catalog to fetch. + * Lists plugins advertised by a registered marketplace. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -71,7 +71,7 @@ public CompletableFuture browse(PluginsMarketpl } /** - * Optional marketplace name; omit to refresh all. + * Re-fetches one or all registered marketplace catalogs. *

* Invokes the method with no params, applying the runtime defaults. * @@ -84,7 +84,7 @@ public CompletableFuture refresh() { } /** - * Optional marketplace name; omit to refresh all. + * Re-fetches one or all registered marketplace catalogs. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoApi.java new file mode 100644 index 0000000000..3db04fe14a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoApi.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code repo} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerRepoApi { + + private final RpcCaller caller; + + /** API methods for the {@code repo.settings} sub-namespace. */ + final ServerRepoSettingsApi settings; + + /** @param caller the RPC transport function */ + ServerRepoApi(RpcCaller caller) { + this.caller = caller; + this.settings = new ServerRepoSettingsApi(caller); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java new file mode 100644 index 0000000000..247545adbc --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code repo.settings} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerRepoSettingsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerRepoSettingsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Atomically edits one allowed top-level repository setting. Reads the raw file, preserves unrelated keys, applies one scalar or list edit, validates the result and writes under one file lock, so concurrent sibling or list edits are not lost. A malformed or unsafe existing file returns `invalid` without a write; rejected keys, invalid values and I/O errors reject the call. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture edit(RepoSettingsEditParams params) { + return caller.invoke("repo.settings.edit", params, SettingsEditResult.class); + } + + /** + * Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture readRaw(RepoSettingsReadRawParams params) { + return caller.invoke("repo.settings.readRaw", params, RepoSettingsReadRawResult.class); + } + + /** + * Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeKey(RepoSettingsWriteKeyParams params) { + return caller.invoke("repo.settings.writeKey", params, Void.class); + } + + /** + * Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeAll(RepoSettingsWriteAllParams params) { + return caller.invoke("repo.settings.writeAll", params, Void.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java index 7eb9aa0118..51b83f9864 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java @@ -25,6 +25,20 @@ public final class ServerRpc { private final RpcCaller caller; + /** API methods for the {@code sandbox} namespace. */ + public final ServerSandboxApi sandbox; + /** API methods for the {@code persistence} namespace. */ + final ServerPersistenceApi persistence; + /** API methods for the {@code user} namespace. */ + public final ServerUserApi user; + /** API methods for the {@code repo} namespace. */ + final ServerRepoApi repo; + /** API methods for the {@code featureFlags} namespace. */ + final ServerFeatureFlagsApi featureFlags; + /** API methods for the {@code permissions} namespace. */ + final ServerPermissionsApi permissions; + /** API methods for the {@code managedSettings} namespace. */ + public final ServerManagedSettingsApi managedSettings; /** API methods for the {@code environments} namespace. */ public final ServerEnvironmentsApi environments; /** API methods for the {@code host} namespace. */ @@ -33,8 +47,6 @@ public final class ServerRpc { public final ServerHooksApi hooks; /** API methods for the {@code models} namespace. */ public final ServerModelsApi models; - /** API methods for the {@code sandbox} namespace. */ - public final ServerSandboxApi sandbox; /** API methods for the {@code tools} namespace. */ public final ServerToolsApi tools; /** API methods for the {@code account} namespace. */ @@ -45,6 +57,8 @@ public final class ServerRpc { public final ServerMcpApi mcp; /** API methods for the {@code extensions} namespace. */ public final ServerExtensionsApi extensions; + /** API methods for the {@code instructions} namespace. */ + public final ServerInstructionsApi instructions; /** API methods for the {@code skills} namespace. */ public final ServerSkillsApi skills; /** API methods for the {@code catalog} namespace. */ @@ -53,14 +67,16 @@ public final class ServerRpc { public final ServerPluginsApi plugins; /** API methods for the {@code agents} namespace. */ public final ServerAgentsApi agents; - /** API methods for the {@code instructions} namespace. */ - public final ServerInstructionsApi instructions; + /** API methods for the {@code globalState} namespace. */ + final ServerGlobalStateApi globalState; /** API methods for the {@code commands} namespace. */ public final ServerCommandsApi commands; - /** API methods for the {@code user} namespace. */ - public final ServerUserApi user; - /** API methods for the {@code managedSettings} namespace. */ - public final ServerManagedSettingsApi managedSettings; + /** API methods for the {@code gitHubRepository} namespace. */ + final ServerGitHubRepositoryApi gitHubRepository; + /** API methods for the {@code gitHubOwners} namespace. */ + final ServerGitHubOwnersApi gitHubOwners; + /** API methods for the {@code git} namespace. */ + final ServerGitApi git; /** API methods for the {@code runtime} namespace. */ public final ServerRuntimeApi runtime; /** API methods for the {@code sessionFs} namespace. */ @@ -71,6 +87,8 @@ public final class ServerRpc { public final ServerSessionsApi sessions; /** API methods for the {@code agentRegistry} namespace. */ public final ServerAgentRegistryApi agentRegistry; + /** API methods for the {@code connectors} namespace. */ + public final ServerConnectorsApi connectors; /** * Creates a new server RPC client. @@ -79,33 +97,42 @@ public final class ServerRpc { */ public ServerRpc(RpcCaller caller) { this.caller = caller; + this.sandbox = new ServerSandboxApi(caller); + this.persistence = new ServerPersistenceApi(caller); + this.user = new ServerUserApi(caller); + this.repo = new ServerRepoApi(caller); + this.featureFlags = new ServerFeatureFlagsApi(caller); + this.permissions = new ServerPermissionsApi(caller); + this.managedSettings = new ServerManagedSettingsApi(caller); this.environments = new ServerEnvironmentsApi(caller); this.host = new ServerHostApi(caller); this.hooks = new ServerHooksApi(caller); this.models = new ServerModelsApi(caller); - this.sandbox = new ServerSandboxApi(caller); this.tools = new ServerToolsApi(caller); this.account = new ServerAccountApi(caller); this.secrets = new ServerSecretsApi(caller); this.mcp = new ServerMcpApi(caller); this.extensions = new ServerExtensionsApi(caller); + this.instructions = new ServerInstructionsApi(caller); this.skills = new ServerSkillsApi(caller); this.catalog = new ServerCatalogApi(caller); this.plugins = new ServerPluginsApi(caller); this.agents = new ServerAgentsApi(caller); - this.instructions = new ServerInstructionsApi(caller); + this.globalState = new ServerGlobalStateApi(caller); this.commands = new ServerCommandsApi(caller); - this.user = new ServerUserApi(caller); - this.managedSettings = new ServerManagedSettingsApi(caller); + this.gitHubRepository = new ServerGitHubRepositoryApi(caller); + this.gitHubOwners = new ServerGitHubOwnersApi(caller); + this.git = new ServerGitApi(caller); this.runtime = new ServerRuntimeApi(caller); this.sessionFs = new ServerSessionFsApi(caller); this.llmInference = new ServerLlmInferenceApi(caller); this.sessions = new ServerSessionsApi(caller); this.agentRegistry = new ServerAgentRegistryApi(caller); + this.connectors = new ServerConnectorsApi(caller); } /** - * Optional message to echo back to the caller. + * Checks server responsiveness and returns protocol information. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -116,7 +143,7 @@ public CompletableFuture ping(PingParams params) { } /** - * Connection-level opt-ins for the `server.connect` handshake. Transport authentication is consumed by the native protocol boundary before dispatch. + * Performs the SDK server connection handshake and validates the optional connection token. Marked internal because this is JSON-RPC transport plumbing invoked automatically by an SDK client's own `connect()` wrapper, not a user-facing method. Stays internal as long as the SDK client owns the handshake; would only become public if the SDK ever exposed the raw schema surface to consumers without a connection wrapper. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -127,7 +154,7 @@ CompletableFuture connect(ConnectParams params) { } /** - * Invokes {@code registerExtensionLaunchProvider}. + * Registers the calling SDK client as the per-entrypoint extension launch provider. Call before creating any sessions. When omitted, the runtime uses its built-in extension launcher. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRuntimeApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRuntimeApi.java index e57db70946..d09f784d8d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRuntimeApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRuntimeApi.java @@ -27,7 +27,7 @@ public final class ServerRuntimeApi { } /** - * Invokes {@code runtime.shutdown}. + * Gracefully shuts down an SDK-owned runtime. The response is sent only after cleanup completes; callers may then terminate the owned runtime process. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java index 2634955e4a..2db9adfedd 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java @@ -23,15 +23,142 @@ public final class ServerSandboxApi { /** API methods for the {@code sandbox.proxyCa} sub-namespace. */ public final ServerSandboxProxyCaApi proxyCa; + /** API methods for the {@code sandbox.proxySecret} sub-namespace. */ + final ServerSandboxProxySecretApi proxySecret; + /** API methods for the {@code sandbox.settings} sub-namespace. */ + final ServerSandboxSettingsApi settings; /** @param caller the RPC transport function */ ServerSandboxApi(RpcCaller caller) { this.caller = caller; this.proxyCa = new ServerSandboxProxyCaApi(caller); + this.proxySecret = new ServerSandboxProxySecretApi(caller); + this.settings = new ServerSandboxSettingsApi(caller); } /** - * Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. + * Raises a user's sandbox settings to an administrator's managed sandbox floor and returns the result a session should actually run under. The floor can only tighten: an enterprise force-on is reflected even when the user's own `enabled` is false, and a user cannot lower a setting the floor raised. The result is normalized through the declared sandbox shape, so a key reorder or an undeclared passthrough key is not mistaken for a policy change by callers that diff two results. A host must call this rather than merge the two layers itself, because reimplementing the direction of the fold is what turns an administrator's floor into a suggestion. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveFlooredConfig(SandboxResolveFlooredConfigParams params) { + return caller.invoke("sandbox.resolveFlooredConfig", params, SandboxResolveFlooredConfigResult.class); + } + + /** + * Builds the effective filesystem policy one `@`-file picker checks its suggestions against, so Git discovery and grant canonicalization run once for the picker's lifetime instead of on every debounced keystroke. Returns no policy when the sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant list itself, because the picker's grants are narrower than a file tool's — the same path a built-in tool may read can be one the picker must not offer. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture preparePickerPolicy(SandboxPreparePickerPolicyParams params) { + return caller.invoke("sandbox.preparePickerPolicy", params, SandboxPreparePickerPolicyResult.class); + } + + /** + * Checks a batch of `@`-file picker suggestions against a policy prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, positionally aligned with the request. Batched deliberately: each check canonicalizes a path component-by-component through the real filesystem, so one call amortizes that over a single hop rather than dozens while the user types. A directory the policy does not itself allow can still be kept as a waypoint to an allowed subtree. An absent policy keeps every candidate. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture filterPickerCandidates(SandboxFilterPickerCandidatesParams params) { + return caller.invoke("sandbox.filterPickerCandidates", params, SandboxFilterPickerCandidatesResult.class); + } + + /** + * The sandbox a single named feature actually launches under, which is not the same as the session's sandbox. A feature is routed out of the sandbox by its own flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start one server confined and another free. Returns a disabled sandbox rather than an error when the host has no sandbox slice at all, so an absent config and an opted-out feature read alike at the launch site. A host must ask per feature rather than reuse the session config, because reading only `enabled` confines a server the user opted out of, or reports as sandboxed one that is not. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveForOptional(SandboxResolveForOptionalParams params) { + return caller.invoke("sandbox.resolveForOptional", params, SandboxEffectiveForOptionalResult.class); + } + + /** + * Reports whether this machine can run an OS-level command sandbox at all. A host must ask before it offers sandboxing, because the answer is a property of the machine rather than of any setting: on Linux it depends on bubblewrap being installed, and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a process the first time, so the answer is cached for the life of the runtime. A host that assumes support and enables the sandbox anyway produces a session in which every shell command fails. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkPlatformSupport() { + return caller.invoke("sandbox.checkPlatformSupport", java.util.Map.of(), Boolean.class); + } + + /** + * Reports whether this Windows host's BaseContainer implementation can reach the host's loopback interface directly, which is what a local-network policy needs to avoid routing through the egress proxy. Like `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather than of any setting, and resolving it the first time spawns a platform probe. A host that offers the direct local-network option on a machine that lacks the capability produces a session whose sandboxed commands cannot reach local services. Always false off Windows. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkWindowsHostLoopbackSupport() { + return caller.invoke("sandbox.checkWindowsHostLoopbackSupport", java.util.Map.of(), Boolean.class); + } + + /** + * The explanation a host shows when it refuses an explicit request to turn the sandbox on for a machine that cannot run one. Carries the platform-specific remedy — install bubblewrap, update Windows — and the documentation link, so a host that got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason and cannot describe the same machine differently from the runtime's own spawn path. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnsupportedMessage() { + return caller.invoke("sandbox.getUnsupportedMessage", java.util.Map.of(), String.class); + } + + /** + * The notice a host shows when a stored `sandbox` setting is being ignored for this session because the machine cannot enforce it. Distinct from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports that a setting the user already saved is inert, states that commands will run unsandboxed, and confirms the stored setting itself is left alone. A host that stays silent here leaves the user believing a sandbox is active. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnsupportedSettingDisabledNotice() { + return caller.invoke("sandbox.getUnsupportedSettingDisabledNotice", java.util.Map.of(), String.class); + } + + /** + * The warning a host prints at startup when a session asked for a sandbox on a machine that cannot run one. The third of the unsupported notices, and the only one that depends on the policy in force: it names the remedy the reader can actually act on, which is the stored setting for an unmanaged host, an administrator for a managed one, and waiting for the policy to resolve when the sandbox stayed on only because the policy could not be determined. Returns no notice when the machine does support a sandbox, so a host can call it unconditionally on the startup path. A host that composes its own warning tells a managed user to change a setting their policy will overwrite. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnsupportedStartupNotice(SandboxGetUnsupportedStartupNoticeParams params) { + return caller.invoke("sandbox.getUnsupportedStartupNotice", params, SandboxUnsupportedStartupNoticeResult.class); + } + + /** + * Whether one slash command stays reachable while sandbox enforcement is unavailable and the session is otherwise blocked. The permitted set is deliberately narrow — commands that only report state, and the few that let the user repair or leave the situation — and it is keyed on the arguments as well as the name, so `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than keep its own list: a command this returns false for is one the runtime would refuse anyway, and a divergent list either strands the user with no way out or admits a command that acts on an unenforced session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkEnforcementCommand(SandboxCheckEnforcementCommandParams params) { + return caller.invoke("sandbox.checkEnforcementCommand", params, Boolean.class); + } + + /** + * Returns the documentation URL a host should point a user at when it declines or downgrades a sandbox setting. The runtime owns the address so every surface cites the same page and a host does not hard-code a link that later moves. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getDocsUrl() { + return caller.invoke("sandbox.getDocsUrl", java.util.Map.of(), SandboxDocsUrlResult.class); + } + + /** + * Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java index 0ffe1733d5..5559a0dbcb 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java @@ -27,7 +27,29 @@ public final class ServerSandboxProxyCaApi { } /** - * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * Reports whether this runtime process can offer installing the sandbox credential-proxy certificate authority into OS trust. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture checkInstallationSupport() { + return caller.invoke("sandbox.proxyCa.checkInstallationSupport", java.util.Map.of(), Boolean.class); + } + + /** + * Reports whether this sandbox configuration uses the credential proxy and can need certificate-authority setup. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture checkRelevance(SandboxProxyCaCheckRelevanceParams params) { + return caller.invoke("sandbox.proxyCa.checkRelevance", params, Boolean.class); + } + + /** + * Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +60,7 @@ public CompletableFuture getStatus(SandboxProxyCa } /** - * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +71,7 @@ public CompletableFuture create(SandboxProxyCaCreate } /** - * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -60,7 +82,7 @@ public CompletableFuture rotate(SandboxProxyCaRotate } /** - * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -71,7 +93,7 @@ public CompletableFuture trust(SandboxProxyCaTrustPar } /** - * Status of the persistent certificate authority of the sandbox credential proxy. + * Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxySecretApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxySecretApi.java new file mode 100644 index 0000000000..1432755fac --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxySecretApi.java @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code sandbox.proxySecret} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerSandboxProxySecretApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerSandboxProxySecretApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Reports where this runtime keeps the sandbox proxy password: the credential store directory and the entry identifier within it. Both are derived from the configuration directory this runtime was started with, so a host does not resolve them itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this runtime's own proxy password rather than a reference the user wrote by hand. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getLocation() { + return caller.invoke("sandbox.proxySecret.getLocation", java.util.Map.of(), SandboxProxySecretLocation.class); + } + + /** + * Reads the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to the on-disk store. Reports an absent value rather than failing when no entry exists. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture get() { + return caller.invoke("sandbox.proxySecret.get", java.util.Map.of(), SandboxProxySecretGetResult.class); + } + + /** + * Stores the sandbox proxy password in the credential store `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether the OS keychain accepted it or it fell back to the on-disk store. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture save(SandboxProxySecretSaveParams params) { + return caller.invoke("sandbox.proxySecret.save", params, SandboxProxySecretSaveResult.class); + } + + /** + * Removes the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to call while clearing a proxy password whose origin is unknown. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture delete() { + return caller.invoke("sandbox.proxySecret.delete", java.util.Map.of(), Void.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxSettingsApi.java new file mode 100644 index 0000000000..4d323a03ac --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxSettingsApi.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code sandbox.settings} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerSandboxSettingsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerSandboxSettingsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Resolves a stored sandbox settings object into the effective one, filling every value the user left unset with its default. Read this to render or reason about the sandbox configuration a session would actually run under, rather than the sparse document the user wrote. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture applyDefaults(SandboxSettingsApplyDefaultsParams params) { + return caller.invoke("sandbox.settings.applyDefaults", params, JsonNode.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSecretsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSecretsApi.java index 7f17687818..ebdcac5e9e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSecretsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSecretsApi.java @@ -27,7 +27,7 @@ public final class ServerSecretsApi { } /** - * Secret values to add to the redaction filter. + * Registers secret values for redaction in session logs and exports. The SDK calls this to inject dynamically generated secret values (e.g., OIDC tokens). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionFsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionFsApi.java index 872702997a..ff48cdfb76 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionFsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionFsApi.java @@ -27,7 +27,7 @@ public final class ServerSessionFsApi { } /** - * Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. + * Registers an SDK client as the session filesystem provider. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionsApi.java index 0b7f099245..fd963c0cbd 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSessionsApi.java @@ -28,7 +28,7 @@ public final class ServerSessionsApi { } /** - * Open a session by creating, resuming, attaching, connecting to a remote, or handing off. + * Creates or resumes a local session and returns the opened session ID. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -39,7 +39,7 @@ public CompletableFuture open(SessionsOpenParams params) { } /** - * Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. + * Creates a new session by forking persisted history from an existing session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -50,7 +50,7 @@ public CompletableFuture fork(SessionsForkParams params) { } /** - * Remote session connection parameters. + * Connects to an existing remote session and exposes it as an SDK session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -61,7 +61,7 @@ public CompletableFuture connect(SessionsConnectParams pa } /** - * Optional source filter, metadata-load limit, and context filter applied to the returned sessions. + * Lists sessions, optionally filtered by source and working-directory context. Returned entries are discriminated by `isRemote`: local entries carry only the lightweight `LocalSessionMetadataValue` shape; remote entries carry the full `RemoteSessionMetadataValue` shape (repository, PR number, taskType, etc.). *

* Invokes the method with no params, applying the runtime defaults. * @@ -74,7 +74,7 @@ public CompletableFuture list() { } /** - * Optional source filter, metadata-load limit, and context filter applied to the returned sessions. + * Lists sessions, optionally filtered by source and working-directory context. Returned entries are discriminated by `isRemote`: local entries carry only the lightweight `LocalSessionMetadataValue` shape; remote entries carry the full `RemoteSessionMetadataValue` shape (repository, PR number, taskType, etc.). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -85,7 +85,7 @@ public CompletableFuture list(SessionsListParams params) { } /** - * Session ID whose persisted metadata should be read. + * Reads lightweight persisted metadata for one local session without opening it. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -96,7 +96,7 @@ CompletableFuture getMetadata(SessionsGetMetadataPara } /** - * Bounded batch request for client-owned metadata from persisted local sessions. + * Reads client-owned metadata for multiple persisted local sessions without opening them. Results preserve request order and report missing, corrupt, unsupported, or temporarily unavailable sessions independently. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -107,7 +107,7 @@ public CompletableFuture> getClientMetadata(SessionsGetClientMetada } /** - * Pagination options for reading an inactive or active local session's persisted event journal. + * Reads a page of durable events directly from a local session's persisted journal without creating, resuming, or activating the session. The first read pins the currently opened journal generation and its byte-length boundary; opaque cursor continuations remain on that generation across runtime-owned compaction, truncation, and rewrite operations, which replace the live path atomically, and events appended after the boundary are excluded. For cold hydration, await the first successful page before activation and establish lossless live-event buffering before resume; merge subsequent live events by ID, preserving persisted order and letting live payloads win. Continuations are process-local, single-use capabilities bound to the originating session and storage context and must be paged sequentially; concurrent or repeated use of the same cursor expires that duplicate read rather than reading the generation twice. A complete snapshot has cursorStatus 'ok' and hasMore false. Snapshots expire after five idle minutes, with at most eight retained per process and idle-only eviction under pressure; completion and cancelled-worker exit release their handles. No transcript copy is created, but retained handles may keep replaced files' disk blocks alive until release. Pages have a soft 1 MiB serialized event-array budget including resolved binary assets; one oversized event is returned alone to guarantee progress. Working memory also includes a record/lookahead and asset resolution; resolving the first binary reference may scan the full pinned generation to build a bounded offset index. If the snapshot expires, is evicted, is cancelled before a continuation is established, or becomes unreadable after an observable unsupported in-place shortening, the continuation returns cursorStatus 'expired' with an empty terminal page and never falls back to a different generation. A missing or initially unreadable journal is an RPC error. Persisted history excludes ephemeral events and may omit payloads that are reconstructed only for an active session; use the active session event stream for post-resume live events. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -118,7 +118,7 @@ public CompletableFuture readPersistedEvents( } /** - * Limit for non-empty local session IDs. + * Lists recent local session IDs that contain user-visible history, omitting housekeeping-only sessions. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -129,7 +129,7 @@ CompletableFuture listNonEmptySessionIds(S } /** - * GitHub task ID to look up. + * Finds the local session bound to a GitHub task ID, if any. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -140,7 +140,7 @@ public CompletableFuture findByTaskId(SessionsFindBy } /** - * UUID prefix to resolve to a unique session ID. + * Resolves a UUID prefix to a unique session ID, if exactly one session matches. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -151,7 +151,7 @@ public CompletableFuture findByPrefix(SessionsFindBy } /** - * Optional working-directory context used to score session relevance. + * Returns the most-relevant prior session for a given working-directory context. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -162,7 +162,7 @@ public CompletableFuture getLastForContext(Sess } /** - * Session ID whose event-log file path to compute. + * Computes the absolute path to a session's persisted events.jsonl file. Internal: filesystem paths are only meaningful in-process (CLI and runtime share a filesystem). Currently used by the CLI's contribution-graph feature to read historical events directly. Remote SDK consumers must not depend on this; a proper event-query API would replace it if the contribution graph ever needed to work over the wire. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -173,7 +173,7 @@ CompletableFuture getEventFilePath(SessionsGetEv } /** - * Map of sessionId -> on-disk size in bytes for each session's workspace directory. + * Returns the on-disk byte size of each session's workspace directory. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -184,7 +184,7 @@ public CompletableFuture getSizes() { } /** - * Session IDs to test for live in-use locks. + * Returns the subset of the supplied session IDs that are currently held by another running process. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -195,7 +195,7 @@ public CompletableFuture checkInUse(SessionsCheckInUse } /** - * Session ID to look up the persisted remote-steerable flag for. + * Returns a session's persisted remote-steerable flag, if any has been recorded. Internal: this is CLI-specific book-keeping used by `--continue` / `--resume` to inherit the prior session's remote-steerable preference. SDK consumers that want similar behavior should manage their own persistence around start/stop calls rather than relying on this runtime-side flag. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -206,7 +206,7 @@ CompletableFuture getPersistedRemoteS } /** - * Session ID to close. + * Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -217,7 +217,7 @@ public CompletableFuture close(SessionsCloseParams params) { } /** - * Session IDs to close, deactivate, and delete from disk. + * Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -228,7 +228,7 @@ public CompletableFuture bulkDelete(SessionsBulkDelete } /** - * Session ID to delete from disk. + * Deletes one local session from disk after running the same lifecycle hooks as the session manager. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -239,7 +239,7 @@ CompletableFuture delete(SessionsDeleteParams params) { } /** - * Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + * Deletes sessions older than the given threshold, with optional dry-run and exclusion list. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -250,7 +250,7 @@ public CompletableFuture pruneOld(SessionsPruneOldParams } /** - * Session ID whose pending events should be flushed to disk. + * Flushes a session's pending events to disk. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -261,7 +261,7 @@ public CompletableFuture save(SessionsSaveParams params) { } /** - * Session ID whose in-use lock should be released. + * Releases the in-use lock held by this process for a session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -272,7 +272,7 @@ public CompletableFuture releaseLock(SessionsReleaseLockParams params) { } /** - * Session metadata records to enrich with summary and context information. + * Backfills missing summary and context fields on the supplied session metadata records. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -283,7 +283,40 @@ public CompletableFuture enrichMetadata(SessionsEn } /** - * Active session ID and an optional flag for deferring repo-level hooks until folder trust. + * Creates the workspace record for a session that has not been opened yet. A host that hands a session off to another application — writing the record and then launching that application against the session ID — needs the record on disk before any session exists to carry it, which the session-scoped workspace methods cannot do. Replaces any existing record and resets the checkpoint index. When writing to the local filesystem, a stored `fork_count` survives on disk. Returns the record it built, so a surviving stored `fork_count` can differ from the answer. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture createWorkspace(SessionsCreateWorkspaceParams params) { + return caller.invoke("sessions.createWorkspace", params, SessionsCreateWorkspaceResult.class); + } + + /** + * Reads a session's workspace record straight from disk, without opening the session. Resuming by session ID has to know where the session lives before it can connect, so the lookup cannot come from the session-scoped workspace methods, which resolve their location from a live session's context. Returns no record when the file is absent. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadWorkspace(SessionsLoadWorkspaceParams params) { + return caller.invoke("sessions.loadWorkspace", params, SessionsLoadWorkspaceResult.class); + } + + /** + * Merges fields into a session's workspace record on disk, creating the record when it is absent. The counterpart to `sessions.loadWorkspace`, for the same before-the-session-exists case. It preserves stored workspace-schema fields the request does not supply, does not preserve stored keys outside the workspace schema, and never replaces a stored `fork_count`. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture updateWorkspaceFields(SessionsUpdateWorkspaceFieldsParams params) { + return caller.invoke("sessions.updateWorkspaceFields", params, Void.class); + } + + /** + * Reloads user, plugin, and (optionally) repo hooks on the active session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -294,7 +327,7 @@ public CompletableFuture reloadPluginHooks(SessionsReloadPluginHooksParams } /** - * Active session ID whose deferred repo-level hooks should be loaded. + * Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -305,7 +338,7 @@ public CompletableFuture loadDeferredRepoHo } /** - * Manager-wide additional plugins to register; replaces any previously-configured set. + * Replaces the manager-wide additional plugins registered with the session manager. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -316,7 +349,7 @@ public CompletableFuture setAdditionalPlugins(SessionsSetAdditionalPlugins } /** - * Session ID whose board entry count should be returned. + * Gets the dynamic-context board entry count associated with a session, when available. Internal: this exists solely so CLI telemetry events (`rem_spawn_gate`, `rem_consolidation_complete`) can pair START / END board counts around the detached rem-agent spawn. "Dynamic context board" is a runtime-internal concept that is not part of the public SDK contract; the long-term plan is to relocate the telemetry emission into the runtime so this method can be deleted entirely. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -327,7 +360,7 @@ CompletableFuture getBoardEntryCount(SessionsG } /** - * Parameters for attaching the remote-control singleton to a session. + * Attaches the runtime-managed remote-control singleton to a session, awaiting initial setup. If remote control is already attached to a different session, the singleton is transferred (preserving the underlying Mission Control connection). Returns the final status. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -338,7 +371,7 @@ public CompletableFuture startRemoteControl(Se } /** - * Parameters for atomically rebinding the remote-control singleton. + * Atomically rebinds the remote-control singleton to a different session, preserving the underlying Mission Control connection. When `expectedFromSessionId` is provided and does not match the singleton's current `attachedSessionId`, the transfer is rejected with `transferred: false` and the current status is returned unchanged. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -349,7 +382,7 @@ public CompletableFuture transferRemoteCont } /** - * Patch for the singleton's steering state. + * Patches the steering state of the active remote-control singleton. When remote control is off, this is a no-op and the off status is returned. Today only `enabled: true` is actionable on the underlying exporter; passing `false` is reserved for future use. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -360,7 +393,7 @@ public CompletableFuture setRemoteContro } /** - * Parameters for stopping the remote-control singleton. + * Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). *

* Invokes the method with no params, applying the runtime defaults. * @@ -373,7 +406,7 @@ public CompletableFuture stopRemoteControl() { } /** - * Parameters for stopping the remote-control singleton. + * Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -384,7 +417,7 @@ public CompletableFuture stopRemoteControl(Sess } /** - * Wrapper for the singleton's current status. + * Returns the current state of the remote-control singleton, including the attached session id and frontend URL when active. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -395,7 +428,7 @@ public CompletableFuture getRemoteControlS } /** - * Params to attach or detach an in-process ExtensionController delegate. + * Attaches (or detaches) an in-process ExtensionController delegate for the given session in a local host adapter. Pass `controller: undefined` to detach. Internal because the controller cannot cross the JSON-RPC boundary; the runtime manages its own session extension service. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java index 2f77e8da88..a3e7dc7c58 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -34,7 +35,7 @@ public final class ServerSkillsApi { } /** - * Side-effect-free planning of one verified Agent Finder Skill candidate. + * Plans installation of a verified Agent Finder Skill candidate without writing files. The returned review is safe to present to a user and installing always leaves the Skill disabled until separately enabled. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -45,7 +46,7 @@ public CompletableFuture planInstall(SkillsPl } /** - * Applies exactly one retained verified Skill installation plan. + * Consumes one verified Skill installation plan, requests explicit human consent through installations.confirm on the original connection, then revalidates and installs the Skill disabled. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -56,7 +57,7 @@ public CompletableFuture applyInstall(SkillsApplyInstal } /** - * Read-only preparation of one owned Skill removal under fresh selected-session authority. + * Prepares a read-only removal plan for an owned verified Agent Finder Skill installation. Uninstall planning is never gated by the Skill-install feature flag. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -67,7 +68,7 @@ public CompletableFuture planUninstall(Skills } /** - * One-use application of the exact retained Skill removal plan. + * Consumes an owned Skill removal plan, requests explicit human consent through installations.confirm, refuses drift, and removes the exact owned files through quarantine. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -78,7 +79,7 @@ public CompletableFuture applyUninstall(SkillsApplyUnin } /** - * Optional project paths and additional skill directories to include in discovery. + * Discovers skills across global and project sources. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -89,7 +90,7 @@ public CompletableFuture discover(SkillsDiscoverParams par } /** - * Optional project paths to enumerate. + * Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -99,4 +100,17 @@ public CompletableFuture getDiscoveryPaths(Skills return caller.invoke("skills.getDiscoveryPaths", params, SkillsGetDiscoveryPathsResult.class); } + /** + * Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getDiscoveryPaths(SkillsGetDiscoveryPathsRequest request) { + return caller.invoke("skills.getDiscoveryPaths", Objects.requireNonNull(request, "request"), SkillsGetDiscoveryPathsResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsConfigApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsConfigApi.java index c29770bf14..35cf2e2ef1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsConfigApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsConfigApi.java @@ -27,7 +27,7 @@ public final class ServerSkillsConfigApi { } /** - * Skill names to mark as disabled in global configuration, replacing any previous list. + * Replaces the global list of disabled skills. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture setDisabledSkills(SkillsConfigSetDisabledSkillsPa } /** - * Adds or removes a single skill from the global disabled list, leaving every other entry untouched. + * Atomically adds or removes one skill from the disabled list. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsInstallationsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsInstallationsApi.java index e0d0afe72a..51029bc363 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsInstallationsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsInstallationsApi.java @@ -27,7 +27,7 @@ public final class ServerSkillsInstallationsApi { } /** - * Inventory request under an explicitly selected existing session. + * Lists owned verified Agent Finder Skill installations for the selected existing session. Listing is never gated by the Skill-install feature flag. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -38,7 +38,7 @@ public CompletableFuture list(SkillsInstallat } /** - * Inventory request under an explicitly selected existing session. + * Reconciles interrupted owned Skill installation work for the selected existing session, then inspects owned inventory. Recovery is never gated by the Skill-install feature flag. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture recover(SkillsInstal } /** - * Existing-operation control. A new session selector is deliberately not accepted. + * Inspects a known Skill installation operation on its original runtime connection. Status is never gated by the Skill-install feature flag. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -60,7 +60,7 @@ public CompletableFuture status(SkillsInstall } /** - * Existing-operation control. A new session selector is deliberately not accepted. + * Requests cancellation of a known Skill installation operation before commit. Already-started durable work requires recovery instead of silent replay. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -71,7 +71,7 @@ public CompletableFuture cancel(SkillsInstall } /** - * Persisted enablement update for one owned Skill installation. + * Atomically persists enablement for one owned Agent Finder Skill and reconciles the selected bound session. Enablement is installation-scoped by receipt identity and is never gated by the Skill-install feature flag. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerToolsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerToolsApi.java index 2938010010..6f3b3b8759 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerToolsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerToolsApi.java @@ -27,7 +27,7 @@ public final class ServerToolsApi { } /** - * Optional model identifier whose tool overrides should be applied to the listing. + * Lists built-in tools available for a model. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java index 665cfb107a..75c8e38934 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java @@ -7,6 +7,7 @@ package com.github.copilot.generated.rpc; +import com.fasterxml.jackson.databind.JsonNode; import com.github.copilot.CopilotExperimental; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -27,18 +28,161 @@ public final class ServerUserSettingsApi { } /** - * Invokes {@code user.settings.reload}. + * Adds or removes one hook key in the user `disabledHooks` setting, rewriting settings.json in place and leaving every other setting untouched. Reports a typed outcome rather than failing the call, so a host can tell an unparseable settings file apart from a write that could not complete. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 */ @CopilotExperimental - public CompletableFuture reload() { - return caller.invoke("user.settings.reload", java.util.Map.of(), Void.class); + CompletableFuture setHookDisabled(UserSettingsSetHookDisabledParams params) { + return caller.invoke("user.settings.setHookDisabled", params, UserSettingsSetHookDisabledResult.class); } /** - * Per-key metadata for every known user setting (settings.json overlaid with the legacy config.json, config.json wins), including settings left at their default. Excludes repository- and enterprise-managed overrides. + * Reads the user's settings document exactly as `user.settings.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the settings read match the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `user.settings.load`. Hook-validation relaxations are deliberately not caller-supplied: they continue to come from the server's environment, so a consumer cannot widen the host's hook policy through this method. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadForConfigDir(UserSettingsLoadForConfigDirParams params) { + return caller.invoke("user.settings.loadForConfigDir", params, JsonNode.class); + } + + /** + * Reads a repository's checked-in settings document as stored, normalized, together with any diagnostic raised while reading it. This is the repository half of the layering `user.settings.get` reports: `user.settings.load` reads the user's own document, and this reads the one a repository checks in to govern the keys `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, or that sets a key a repository may not govern, is reported through `warning` while the settings that did load are still returned, so a consumer surfaces the diagnostic and continues rather than failing the session. When `repoRoot` is the user's home directory the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as repository policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadRepo(UserSettingsLoadRepoParams params) { + return caller.invoke("user.settings.loadRepo", params, UserSettingsLoadRepoResult.class); + } + + /** + * Reads a repository's settings and merges them over a supplied user layer in one step, returning the settings a consumer should act on inside that repository. Use this rather than reading the two layers separately: the merge is per setting and collection-aware, so a repository adds to the collections it is allowed to influence without replacing the user's own entries, and a whole-document overlay would get that wrong. Any diagnostic raised while reading the repository layer is returned rather than printed, so the consumer decides how to surface it; the settings that did load are merged regardless. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadAndMergeRepo(UserSettingsLoadAndMergeRepoParams params) { + return caller.invoke("user.settings.loadAndMergeRepo", params, UserSettingsLoadAndMergeRepoResult.class); + } + + /** + * Reports the on-disk path of the settings document `user.settings.load` and `user.settings.set` read and write. Resolved the same way those methods resolve it, so a host that shows or opens the settings file names the file the runtime actually uses, including the extensionless legacy `settings` file when that is what is present. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getPath() { + return caller.invoke("user.settings.getPath", java.util.Map.of(), UserSettingsPathResult.class); + } + + /** + * Reads the user's stored settings together with the diagnostic raised while reading them. This is `user.settings.load` plus the reason part of the document was ignored: that one answers the document alone, so a caller cannot tell a clean read from a salvaged one. Read this when the caller is about to write the file back, where accepting a partial parse would discard every value the loader could not read. The settings that did load are still reported alongside the warning, so a consumer may surface it and continue instead of failing. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadWithWarning() { + return caller.invoke("user.settings.loadWithWarning", java.util.Map.of(), UserSettingsLoadWithWarningResult.class); + } + + /** + * Folds a user settings layer over a managed (enterprise policy) layer and returns the merged settings. The managed layer's governance keys win, `autoTier` resolves through its overridable form, and the two per-entry control maps (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped back from the managed layer, so each entry an administrator declares wins while the user keeps control of the rest. The parameters are named for their layers rather than being a generic base/override pair: nothing about a settings object identifies which layer produced it, so the runtime cannot detect a transposed call, and transposing one resolves the governance keys in the user's favour instead of the administrator's. Supplying only one layer returns it unchanged, and supplying neither returns an empty object. Rejects a managed `autoTier` that is neither a user-configurable tier nor a single-key overridable form, rather than silently dropping it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture mergeManagedAndUser(UserSettingsMergeManagedAndUserParams params) { + return caller.invoke("user.settings.mergeManagedAndUser", params, UserSettingsMergeManagedAndUserResult.class); + } + + /** + * Folds a repository's settings layer into the user layer. Each repo-overridable key carries a directional policy chosen so a repository can only add restrictions and never relax the user's own. The two per-entry managed control maps are the exception those directional rules cannot express — a repository may legitimately enable plugins and declare marketplaces — so they are re-stamped afterwards from the runtime's ambient managed policy. That makes the result depend on the runtime process's managed state and not on the arguments alone: a host must call this rather than reimplement the fold, or a repository could relax a restriction the administrator imposed. Rejects when either layer is not a JSON object. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture mergeRepoValue(UserSettingsMergeRepoValueParams params) { + return caller.invoke("user.settings.mergeRepoValue", params, UserSettingsMergeRepoValueResult.class); + } + + /** + * Runs the one-time migration that moves a staff account's update channel to stable, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file, re-reads the completion stamp inside it, and returns `current` rather than migrating twice, so two hosts racing at startup cannot both migrate. Only a `migrated` status means the persisted settings changed and the caller should reload them. An account on the experimental channel is deliberately left alone and reported as `excluded-experimental`. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture migrateStaffUpdateChannelOnce(UserSettingsMigrateStaffUpdateChannelOnceParams params) { + return caller.invoke("user.settings.migrateStaffUpdateChannelOnce", params, UserSettingsMigrateStaffUpdateChannelOnceResult.class); + } + + /** + * Runs the one-time reset that clears a staff account's pinned model selection, and reports the timestamp the host should record. Idempotent and self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the timestamp it recorded gets `didReset: false` rather than a second reset. It applies to staff accounts only; any other account is reported as not reset without the settings document being opened. Only `didReset: true` means the persisted settings changed, and only then are the updated settings returned for the host to adopt. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resetStaffModelSelectionOnce(UserSettingsResetStaffModelSelectionOnceParams params) { + return caller.invoke("user.settings.resetStaffModelSelectionOnce", params, UserSettingsResetStaffModelSelectionOnceResult.class); + } + + /** + * Reports the top-level keys in the user settings document that the runtime does not recognize, phrased for display to the user. This is a separate question from the warning `user.settings.loadWithWarning` returns: that one describes parts of the document the loader had to ignore to load the rest, whereas an unknown key parses cleanly and is simply not a setting, so a host that surfaces only the load warning silently accepts a misspelled key that will never take effect. Nothing is reported when the document is absent, unreadable, or failed to load, because an unknown-key list derived from a document the runtime could not read would be misleading rather than helpful. Inspection never modifies the document. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnknownKeysWarning(UserSettingsGetUnknownKeysWarningParams params) { + return caller.invoke("user.settings.getUnknownKeysWarning", params, UserSettingsUnknownKeysWarningResult.class); + } + + /** + * Resolves the effective runtime settings for a host that is about to start a session, layering the given overrides over the settings documents, the environment and the platform defaults. A host cannot assemble this itself: the precedence between a user document, a repository document, the managed layers and the environment is the runtime's own rule, and a host that re-implements it drifts from the server it is configuring. The working directory, environment and platform are taken as arguments rather than read from the server process, so a host resolving settings for a directory other than its own gets that directory's answer. Nothing is written; this only computes. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture buildRuntime(UserSettingsBuildRuntimeParams params) { + return caller.invoke("user.settings.buildRuntime", params, JsonNode.class); + } + + /** + * Runs the one-time migration that moves a staff account's log level to the current default, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file and re-reads the completion stamp inside it, so two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the persisted settings, and the settings it returns are the document re-read after the write, so a host should adopt them rather than reloading separately and racing the next writer. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture migrateStaffLogLevelOnce(UserSettingsMigrateStaffLogLevelOnceParams params) { + return caller.invoke("user.settings.migrateStaffLogLevelOnce", params, UserSettingsMigrateStaffLogLevelOnceResult.class); + } + + /** + * Runs the one-time cleanup that removes obsolete CLI-owned settings and legacy rubber-duck keys from the user's settings document, and reports what it did. Idempotent and safe to call on every startup: with nothing obsolete left it reports `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so a setting written by a newer host is never dropped by an older one, and a document that fails to parse is reported `invalid` and left untouched rather than rewritten from a partial read. The cleaned document is not returned: it is written before this replies, so `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys through `user.settings.unknownKeys` wants this first, because the keys this retires would otherwise be shown to the user as if they were misspelled settings. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture migrateObsoleteOnDisk(UserSettingsMigrateObsoleteOnDiskParams params) { + return caller.invoke("user.settings.migrateObsoleteOnDisk", params, UserSettingsMigrateObsoleteOnDiskResult.class); + } + + /** + * Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,14 +193,124 @@ public CompletableFuture get() { } /** - * Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. + * Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getPaths(UserSettingsGetPathsParams params) { + return caller.invoke("user.settings.getPaths", params, UserSettingsGetPathsResult.class); + } + + /** + * Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture set(UserSettingsSetParams params) { + return caller.invoke("user.settings.set", params, Void.class); + } + + /** + * Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture listGovernanceKeys() { + return caller.invoke("user.settings.listGovernanceKeys", java.util.Map.of(), UserSettingsGovernanceKeysResult.class); + } + + /** + * Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture edit(UserSettingsEditParams params) { + return caller.invoke("user.settings.edit", params, SettingsEditResult.class); + } + + /** + * Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture normalize(UserSettingsNormalizeParams params) { + return caller.invoke("user.settings.normalize", params, UserSettingsNormalizeResult.class); + } + + /** + * Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture diagnoseProblems(UserSettingsDiagnoseProblemsParams params) { + return caller.invoke("user.settings.diagnoseProblems", params, UserSettingsProblemsResult.class); + } + + /** + * Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture applyTopKey(UserSettingsApplyTopKeyParams params) { + return caller.invoke("user.settings.applyTopKey", params, UserSettingsApplyTopKeyResult.class); + } + + /** + * Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeAll(UserSettingsWriteAllParams params) { + return caller.invoke("user.settings.writeAll", params, Void.class); + } + + /** + * Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture update(UserSettingsUpdateParams params) { + return caller.invoke("user.settings.update", params, UserSettingsUpdateResult.class); + } + + /** + * Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadForEdit() { + return caller.invoke("user.settings.loadForEdit", java.util.Map.of(), UserSettingsLoadForEditResult.class); + } + + /** + * Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 */ @CopilotExperimental - public CompletableFuture set(UserSettingsSetParams params) { - return caller.invoke("user.settings.set", params, UserSettingsSetResult.class); + CompletableFuture validate(UserSettingsValidateParams params) { + return caller.invoke("user.settings.validate", params, UserSettingsValidateResult.class); } } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsApi.java index 76b3fdc7e0..2b4f752fdf 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsApi.java @@ -35,7 +35,7 @@ public final class SessionAccountsApi { } /** - * Enumerate request carrying the typed collection query. + * Enumerate a typed accounts collection: the signed-in accounts, or the providers offered for interactive login. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -51,7 +51,7 @@ public CompletableFuture enumerate(SessionAccountsEnumerateP } /** - * Read request carrying the typed datum query. + * Read one typed accounts datum: the active account, a neutral status summary, or the last authentication errors. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -67,7 +67,7 @@ public CompletableFuture get(SessionAccountsGetParams params) { } /** - * Mutation request carrying the typed write command. + * Apply one non-interactive accounts mutation: switch the active account, log an account out, or set credentials from a token. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsLoginApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsLoginApi.java index 5537a0dad2..24e3c6a642 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsLoginApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAccountsLoginApi.java @@ -31,7 +31,7 @@ public final class SessionAccountsLoginApi { } /** - * Begin an interactive login flow for a provider kind. Dispatch is kind-only. + * Begin an interactive login flow for a provider kind (dispatch is kind-only) and return its opaque flow id and first step. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture begin(SessionAccountsL } /** - * Advance an in-flight login flow, optionally fulfilling an input-required step. + * Advance an in-flight login flow, optionally fulfilling an input-required step, and return the next step. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -63,7 +63,7 @@ public CompletableFuture advance(SessionAccountsLoginAdvanceParam } /** - * Cancel an in-flight login flow. + * Cancel an in-flight login flow and release its resources. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAgentApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAgentApi.java index d2499fe3a5..0030c622d0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAgentApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAgentApi.java @@ -31,7 +31,7 @@ public final class SessionAgentApi { } /** - * Controls whether built-in agents and authored prompt text are included. + * Lists agents available to the session. Defaults to custom agents only; pass includeBuiltInAgents to include the effective built-in agents. *

* Invokes the method with no params, applying the runtime defaults. * @@ -44,7 +44,7 @@ public CompletableFuture list() { } /** - * Controls whether built-in agents and authored prompt text are included. + * Lists agents available to the session. Defaults to custom agents only; pass includeBuiltInAgents to include the effective built-in agents. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -60,7 +60,7 @@ public CompletableFuture list(SessionAgentListParams par } /** - * An in-memory authored prompt override for an available agent. + * Sets an in-memory authored prompt override for an available agent. For built-in agents, this replaces only the static base prompt while preserving runtime-owned dynamic prompt composition and behavior. The special `general-purpose` agent is not overrideable. Overrides are not persisted; resumed and forked sessions start without them, so the host must re-apply them. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -76,7 +76,7 @@ public CompletableFuture setPrompt(SessionAgentSetPromptParams params) { } /** - * Identifies the target session. + * Gets the currently selected custom agent for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -87,7 +87,7 @@ public CompletableFuture getCurrent() { } /** - * Name of the custom agent to select for subsequent turns. + * Selects a custom agent for subsequent turns in the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -103,7 +103,7 @@ public CompletableFuture select(SessionAgentSelectPara } /** - * Identifies the target session. + * Clears the selected custom agent and returns the session to the default agent. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -114,7 +114,7 @@ public CompletableFuture deselect() { } /** - * Identifies the target session. + * Reloads custom agent definitions and returns the refreshed list. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAutopilotObjectiveApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAutopilotObjectiveApi.java index ab4058e6b6..8edc125d7e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAutopilotObjectiveApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionAutopilotObjectiveApi.java @@ -29,7 +29,7 @@ public final class SessionAutopilotObjectiveApi { } /** - * Identifies the target session. + * Reads the current canonical autopilot objective state for this session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasActionApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasActionApi.java index 8c6ce4b79e..3e41100db6 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasActionApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasActionApi.java @@ -31,7 +31,7 @@ public final class SessionCanvasActionApi { } /** - * Canvas action invocation parameters. + * Invokes an action on an open canvas instance. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasApi.java index 2fce433e5c..fdcee24883 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasApi.java @@ -38,7 +38,7 @@ public final class SessionCanvasApi { } /** - * Identifies the target session. + * Lists canvases declared for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -49,7 +49,7 @@ public CompletableFuture list() { } /** - * Identifies the target session. + * Lists currently open canvas instances for the live session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -60,7 +60,7 @@ public CompletableFuture listOpen() { } /** - * Canvas open parameters. + * Opens or focuses a canvas instance. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -76,7 +76,7 @@ public CompletableFuture open(SessionCanvasOpenParams p } /** - * Canvas close parameters. + * Closes an open canvas instance. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderApi.java index c68c050f75..90a80dfce0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderApi.java @@ -31,7 +31,7 @@ final class SessionCanvasProviderApi { } /** - * Internal canvas provider registration parameters. + * Registers an internal canvas provider connection and its contributions. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ CompletableFuture register(SessionCanvasProviderRegisterParams params) { } /** - * Internal canvas provider unregistration parameters. + * Unregisters an internal canvas provider connection. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java index a9213671aa..4843040c6e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java @@ -30,6 +30,7 @@ record SessionCanvasProviderRegisterParams( /** Connection identifier for callback routing */ @JsonProperty("connectionId") String connectionId, /** Provider metadata supplied by the host */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("info") Object info, /** Canvas contributions supplied by the provider */ @JsonProperty("canvases") List canvases diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCommandsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCommandsApi.java index 6be3682233..55cd139ae5 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCommandsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCommandsApi.java @@ -31,7 +31,7 @@ public final class SessionCommandsApi { } /** - * Optional filters controlling which command sources to include in the listing. + * Lists slash commands available in the session. *

* Invokes the method with no params, applying the runtime defaults. * @@ -44,7 +44,7 @@ public CompletableFuture list() { } /** - * Optional filters controlling which command sources to include in the listing. + * Lists slash commands available in the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -60,7 +60,7 @@ public CompletableFuture list(SessionCommandsListPara } /** - * Slash command name and optional raw input string to invoke. + * Invokes a slash command in the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -76,7 +76,7 @@ public CompletableFuture invoke(SessionCommandsInv } /** - * The pending slash-command invocation effect to finalize, plus whether the host applied or cancelled it. + * Finalizes persistence associated with a client-applied slash-command effect. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -92,7 +92,7 @@ CompletableFuture finalizeInvocationEffe } /** - * Pending command request ID and an optional error if the client handler failed. + * Reports completion of a pending client-handled slash command. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -108,7 +108,7 @@ public CompletableFuture handlePendin } /** - * Slash command name and argument string to execute synchronously. + * Executes a slash command synchronously and returns any error. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -124,7 +124,7 @@ public CompletableFuture execute(SessionCommandsEx } /** - * Slash-prefixed command string to enqueue for FIFO processing. + * Enqueues a slash command for FIFO processing on the local session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -140,7 +140,7 @@ public CompletableFuture enqueue(SessionCommandsEnqueuePar } /** - * Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). + * Reports whether the host actually executed a queued command and whether to continue processing. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCompletionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCompletionsApi.java index 6b9d8aa252..f9fa5d1dae 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCompletionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCompletionsApi.java @@ -31,7 +31,7 @@ public final class SessionCompletionsApi { } /** - * Identifies the target session. + * Gets the characters that should trigger host-driven completions for the session. Empty disables host-driven completions (e.g. local sessions, or a relay host that does not advertise them). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture getTrigge } /** - * Request host-driven completions for the current composer input. + * Requests host-driven completion items for the current composer input. Returns an empty list when the host has no items or does not support completions. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionConnectedIdeInfo.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionConnectedIdeInfo.java new file mode 100644 index 0000000000..9a2f0bce74 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionConnectedIdeInfo.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The IDE a host is connected to, as reported to the session. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionConnectedIdeInfo( + /** Display name of the connected IDE, for example `VS Code`. */ + @JsonProperty("ideName") String ideName, + /** Absolute path of the workspace folder the IDE has open. */ + @JsonProperty("workspaceFolder") String workspaceFolder +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionConnectorsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionConnectorsApi.java index e192274a87..e69fc59d23 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionConnectorsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionConnectorsApi.java @@ -32,7 +32,7 @@ public final class SessionConnectorsApi { } /** - * Identifies the target session. + * Returns feature availability and bounded polling limits for the EXPERIMENTAL session connector API. This method never performs a Connector service request. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -43,7 +43,7 @@ public CompletableFuture getCapabilities } /** - * Identifies the target session. + * Returns the session account selection, or null. * * @return a future that completes with the {@code ConnectorSessionAccount} value, * or {@code null} when the result is absent. Callers must handle the @@ -58,7 +58,7 @@ public CompletableFuture getAccount() { } /** - * Identifies the target session. + * Returns authoritative session Connector state from current availability, pinned account selection, cached catalog, and live MCP projection without performing a Connector service request. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -69,7 +69,7 @@ public CompletableFuture getStatus() { } /** - * Pins a Connector operation to one host-owned GitHub account through its opaque selection ID. Provider tokens are never accepted. + * Returns the cached Connector catalog for the pinned opaque account selection, fetching it only when this session has no cached catalog. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -85,7 +85,7 @@ public CompletableFuture list(SessionConnectorsList } /** - * Pins a Connector operation to one host-owned GitHub account through its opaque selection ID. Provider tokens are never accepted. + * Refreshes and validates the Connector catalog for the pinned opaque account selection. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -101,7 +101,7 @@ public CompletableFuture refresh(SessionConnecto } /** - * Selects one Connector and the pinned host-owned account used for its service and MCP authorization. + * Initiates an idempotent Connector connection request without opening a browser. Returns connected when the service is immediately authoritative, consent_required with a validated URL, or pending with an opaque continuation ID. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -117,7 +117,7 @@ public CompletableFuture connect(SessionConnectorsConnec } /** - * Selects one Connector and the pinned host-owned account used for its service and MCP authorization. + * Re-initiates an idempotent Connector connection request without browser or UI effects, with the same typed outcomes as connect. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -133,7 +133,7 @@ public CompletableFuture reconnect(SessionConnectorsReco } /** - * Explicitly bounded continuation of a pending Connector connection. + * Continues a pending Connector connection with caller-supplied attempt, interval, and deadline bounds. The runtime never opens the returned consent URL. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -149,7 +149,7 @@ public CompletableFuture continueConnection(SessionConne } /** - * Selects one Connector and the pinned host-owned account used for its service and MCP authorization. + * Disconnects one Connector for the pinned opaque account selection, refreshes the authoritative catalog, and removes its session-owned MCP projection. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -165,7 +165,7 @@ public CompletableFuture disconnect(SessionCo } /** - * Requests authoritative Connector-to-MCP reconciliation for the pinned account. + * Reconciles the authoritative cached or freshly requested Connector catalog into the session Connector MCP projection and returns live status. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -181,7 +181,7 @@ public CompletableFuture reconcile(SessionConn } /** - * Requests authoritative Connector-to-MCP reconciliation for the pinned account. + * Reconciles the authoritative cached or freshly requested Connector catalog into the session Connector MCP projection and returns live status. *

* Accepts the extensible request, including inputs added after the params record. * @@ -196,7 +196,7 @@ public CompletableFuture reconcile(SessionConn } /** - * Pins a Connector operation to one host-owned GitHub account through its opaque selection ID. Provider tokens are never accepted. + * Reconciles the authoritative Connector catalog into the session MCP projection during startup with a bounded deadline and fail-closed cleanup. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -212,7 +212,7 @@ CompletableFuture reconcileForStartup(SessionConnectorsReconcil } /** - * Identifies the target session. + * Removes the runtime-owned Connector MCP projection without changing service-side connections. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionContentExclusionApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionContentExclusionApi.java index eb621e6b49..afddaed971 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionContentExclusionApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionContentExclusionApi.java @@ -31,7 +31,7 @@ public final class SessionContentExclusionApi { } /** - * Local file system absolute paths within the session working directory to check against its content-exclusion policy. + * Checks local file system absolute paths within the session working directory against its content-exclusion policy. Results preserve input order. Unsupported paths/filesystems and unavailable policy evaluation return available false, and callers must treat every requested path as excluded. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCustomizationsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCustomizationsApi.java index ee9134f803..b0183065b0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCustomizationsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCustomizationsApi.java @@ -29,7 +29,7 @@ public final class SessionCustomizationsApi { } /** - * Identifies the target session. + * For local sessions, reconciles repository context and discovered instructions, plugins, skills, agents, hooks, MCP servers, and extensions after files appear or change under the working directory. Independent component failures are returned in outcomes and errors; a rejected call can have partially applied earlier steps. Remote sessions must reload on their agent host instead. The model-facing context is rebuilt on the next turn. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDebugApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDebugApi.java index b2cd030183..ed06730c49 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDebugApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDebugApi.java @@ -31,7 +31,7 @@ public final class SessionDebugApi { } /** - * Options for collecting a session debug bundle with configurable redaction. + * Collects a session debug log bundle into a local archive or staging directory. Logs are redacted by default; redaction can be configured per caller-provided diagnostic entry. The runtime includes session-owned logs by default and accepts caller-provided diagnostic entries so host applications can add their own files without changing this API shape. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDiagnosticsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDiagnosticsApi.java index af4c57837b..d263853aec 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDiagnosticsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionDiagnosticsApi.java @@ -31,7 +31,7 @@ public final class SessionDiagnosticsApi { } /** - * Patch session diagnostic thresholds for explicitly supplied sources. + * Patches configured session diagnostic sources without restarting their producers. Setting a source level to off clears its retained diagnostics and invalidates cursors selecting that source. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture configure(SessionDia } /** - * Cursor-based request for session diagnostics. The default limit is 100 (maximum 500); the default waitMs is zero (maximum 30000). + * Reads a bounded batch of retained session diagnostics for the selected sources. Records are never consumed and each reader advances independently through its opaque cursor. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionEventLogApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionEventLogApi.java index 8ad9b3b1f5..87ad200719 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionEventLogApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionEventLogApi.java @@ -31,7 +31,7 @@ public final class SessionEventLogApi { } /** - * Cursor, batch size, and optional long-poll/filter parameters for reading session events. + * Reads a batch of session events from a cursor, optionally waiting for new events. Supports tail-first reads via `direction: backward`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture read(SessionEventLogReadPara } /** - * Identifies the target session. + * Returns a snapshot of the current tail cursor without consuming events. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -58,7 +58,7 @@ public CompletableFuture tail() { } /** - * Event type to register consumer interest for, used by runtime gating logic. + * Registers consumer interest in an event type for runtime gating purposes. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -74,7 +74,7 @@ public CompletableFuture registerInterest } /** - * Opaque handle previously returned by `registerInterest` to release. + * Releases a consumer's previously-registered interest in an event type. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsApi.java index e21c109684..d4d5837dcc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsApi.java @@ -31,7 +31,7 @@ public final class SessionExtensionsApi { } /** - * Identifies the target session. + * Lists extensions discovered for the session and their current status. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture list() { } /** - * Source-qualified extension identifier to enable for the session. + * Enables an extension for the session and persists the preference when the session has a settings store. Hosts synchronizing effective membership should use extensions.reconcile instead. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +58,7 @@ public CompletableFuture enable(SessionExtensionsEnableParams params) { } /** - * Source-qualified extension identifier to disable for the session. + * Disables an extension for the session and persists the preference when the session has a settings store. Hosts synchronizing effective membership should use extensions.reconcile instead. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -74,7 +74,7 @@ public CompletableFuture disable(SessionExtensionsDisableParams params) { } /** - * Identifies the target session. + * Reloads extension definitions and processes for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -85,7 +85,18 @@ public CompletableFuture reload() { } /** - * Parameters for session.extensions.sendAttachmentsToMessage. + * Host-only reconciliation of authoritative session-effective extension membership and enablement. Refreshes runtime-owned discovery and preferences without persisting settings, installing plugins, or restarting unchanged activations. Returns ExtensionList only after required starts and process/contribution cleanup settle. Takes no caller inventory or overrides. Missing controllers, unready/incomplete discovery, unavailable workspaces, superseded inputs, and lifecycle failures are errors, not empty membership. Independently proven revocations may be applied before an error; retry converges without restarting healthy activations. Error data contains lifecycleChangesApplied and code: extension_reconciliation_host_required, extension_reconciliation_unavailable, extension_reconciliation_not_ready, extension_reconciliation_discovery_failed, extension_reconciliation_workspace_unavailable, extension_reconciliation_superseded, or extension_reconciliation_lifecycle_failed. Mark host reconciliation state applied only on success. On older runtimes, method-not-found must not fall back to global discovery and persistent extension disables. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture reconcile() { + return caller.invoke("session.extensions.reconcile", java.util.Map.of("sessionId", this.sessionId), SessionExtensionsReconcileResult.class); + } + + /** + * 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. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsReconcileParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsReconcileParams.java new file mode 100644 index 0000000000..5e6ac8ef1b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsReconcileParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the target session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsReconcileParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsReconcileResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsReconcileResult.java new file mode 100644 index 0000000000..7d1472c947 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionExtensionsReconcileResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Extensions discovered for the session, with their current status. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionExtensionsReconcileResult( + /** Discovered extensions and their current status */ + @JsonProperty("extensions") List extensions +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionFleetApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionFleetApi.java index ca855b70a9..1c5730cd88 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionFleetApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionFleetApi.java @@ -31,7 +31,7 @@ public final class SessionFleetApi { } /** - * Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. + * Starts fleet mode by submitting the fleet orchestration prompt to the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java index 94a3b8e6d0..f98aa7791d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java @@ -32,7 +32,7 @@ public final class SessionGitHubAuthApi { } /** - * Identifies the target session. + * Gets authentication status and account metadata for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -43,7 +43,7 @@ public CompletableFuture getStatus() { } /** - * New auth credentials to install on the session. Omit to leave credentials unchanged. + * Updates the session's auth credentials used for outbound model and API requests. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -59,7 +59,7 @@ public CompletableFuture setCredentials(S } /** - * Identifies the target session. + * Gets the current authentication information for internal session hosts. * * @return a future that completes with the {@code AuthIdentity} value, * or {@code null} when the result is absent. Callers must handle the @@ -74,7 +74,7 @@ CompletableFuture getCurrentAuthInfo() { } /** - * Identifies the target session. + * Gets all authentication accounts available to the internal session host. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -85,7 +85,7 @@ CompletableFuture> getAllAuthAvailable() { } /** - * Identifies the target session. + * Refreshes Copilot account metadata for the current authentication. * * @return a future that completes with the {@code AuthIdentity} value, * or {@code null} when the result is absent. Callers must handle the @@ -100,7 +100,7 @@ CompletableFuture refreshCopilotUser() { } /** - * Internal GitHub login parameters. + * Logs in a GitHub user through the internal session host. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -116,7 +116,7 @@ CompletableFuture login(SessionGitHubAuthLoginParams params) { } /** - * Parameters for switching the session's active authentication. + * Switches the session to another available authentication. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -132,18 +132,18 @@ CompletableFuture switchToAuth(SessionGitHubAuthSwitchToAuthParams params) } /** - * Identifies the target session. + * Logs out the session's current GitHub authentication. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 */ @CopilotExperimental - CompletableFuture logout() { - return caller.invoke("session.gitHubAuth.logout", java.util.Map.of("sessionId", this.sessionId), Void.class); + CompletableFuture logout() { + return caller.invoke("session.gitHubAuth.logout", java.util.Map.of("sessionId", this.sessionId), Boolean.class); } /** - * Parameters identifying a GitHub authentication to log out. + * Logs out a specific GitHub authentication. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -152,14 +152,14 @@ CompletableFuture logout() { * @since 1.0.0 */ @CopilotExperimental - CompletableFuture logoutUser(SessionGitHubAuthLogoutUserParams params) { + CompletableFuture logoutUser(SessionGitHubAuthLogoutUserParams params) { com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); _p.put("sessionId", this.sessionId); - return caller.invoke("session.gitHubAuth.logoutUser", _p, Void.class); + return caller.invoke("session.gitHubAuth.logoutUser", _p, Boolean.class); } /** - * Identifies the target session. + * Gets validation errors from the most recent authentication attempt. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionHistoryApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionHistoryApi.java index ad44d864de..ccfbfbd17f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionHistoryApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionHistoryApi.java @@ -31,7 +31,7 @@ public final class SessionHistoryApi { } /** - * Optional compaction parameters. + * Compacts the session history to reduce context usage. *

* Invokes the method with no params, applying the runtime defaults. * @@ -44,7 +44,7 @@ public CompletableFuture compact() { } /** - * Optional compaction parameters. + * Compacts the session history to reduce context usage. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -60,7 +60,7 @@ public CompletableFuture compact(SessionHistoryComp } /** - * Identifier of the event to truncate to; this event and all later events are removed. + * Truncates persisted session history to a specific event. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -76,7 +76,7 @@ public CompletableFuture truncate(SessionHistoryTr } /** - * Identifies the target session. + * Lists the user turns that the session can rewind to. Never rejects for a busy session: rewind reads need the session's file-change captures to be settled, so a session that still holds active work answers with `unavailableReason: "session-busy"` and no points, which the caller can retry. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -87,7 +87,7 @@ public CompletableFuture listRewindPoints( } /** - * Event boundary to preview for conversation-and-files rewind. + * Previews the files that a conversation-and-files rewind would restore. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -103,7 +103,7 @@ public CompletableFuture previewRewind(Sessio } /** - * Boundary and mode for rewinding session history. + * Rewinds the session conversation, optionally restoring files changed by the discarded turns. Not crash-atomic: file restore and conversation truncation are separate stores, applied in that order, so a process crash between them can leave the workspace rewound while the conversation still contains the discarded turns. There is no recovery journal; re-running the same rewind is the recovery path for a crash before truncation lands, since file restore is idempotent (already-restored files are reported as skipped) and truncation is re-derived from the still-retained boundary event. After truncation lands that boundary no longer exists, so the same request is rejected; the only stage that can still be outstanding is snapshot pruning, whose failure leaves orphan snapshots the capture store tolerates. The reverse inconsistency cannot occur, because truncation is never applied before file restore succeeds. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -119,7 +119,7 @@ public CompletableFuture rewind(SessionHistoryRewind } /** - * Identifies the target session. + * Cancels any in-progress background compaction on a local session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -130,7 +130,7 @@ public CompletableFuture cancelB } /** - * Identifies the target session. + * Aborts any in-progress manual compaction on a local session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -141,7 +141,7 @@ public CompletableFuture abortManualC } /** - * Identifies the target session. + * Produces a markdown summary of the session's conversation context for hand-off scenarios. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -152,7 +152,7 @@ public CompletableFuture summarizeForHa } /** - * Parameters for clearing the conversation and seeding the window that replaces it. + * Clears the session's conversation history, keeping only system and developer messages, and seeds the fresh context window with a first user message. Must be called from inside a tool handler: the clear has to drop the results of the tool calls its wipe orphans, and it rejects when no tool call is in flight. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionInstructionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionInstructionsApi.java index 0a1cf9ba21..1252fa8f59 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionInstructionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionInstructionsApi.java @@ -29,7 +29,7 @@ public final class SessionInstructionsApi { } /** - * Identifies the target session. + * Gets instruction sources loaded for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -40,7 +40,7 @@ public CompletableFuture getSources() { } /** - * Identifies the target session. + * For local sessions, invalidates instruction discovery and the model-facing prompt, then returns freshly discovered sources. The updated prompt takes effect on the next turn. Remote sessions must reload on their agent host instead. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLimitPredictionApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLimitPredictionApi.java index a64f82afae..b28b54bd37 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLimitPredictionApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLimitPredictionApi.java @@ -31,7 +31,7 @@ public final class SessionLimitPredictionApi { } /** - * Parameters for predicting an AI-credit session limit. Omitting `modelId` uses the session's currently selected model. + * Predicts an AI-credit session limit for the session's resolved model. Returns an unavailable result instead of falling back when the current model is unresolved auto. *

* Invokes the method with no params, applying the runtime defaults. * @@ -44,7 +44,7 @@ public CompletableFuture predict() { } /** - * Parameters for predicting an AI-credit session limit. Omitting `modelId` uses the session's currently selected model. + * Predicts an AI-credit session limit for the session's resolved model. Returns an unavailable result instead of falling back when the current model is unresolved auto. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLspApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLspApi.java index c965007d43..2b20bd44e3 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLspApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionLspApi.java @@ -31,7 +31,7 @@ public final class SessionLspApi { } /** - * Parameters for (re)loading the merged LSP configuration set. + * Loads the merged LSP configuration set for the session's working directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedPermissions.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedPermissions.java index 6bf568c985..c8193260d1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedPermissions.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedPermissions.java @@ -24,11 +24,15 @@ public record SessionManagedPermissions( /** When set to `disable`, prevents bypass/allow-all permission modes. Advisory auto-approval remains available because normal prompt paths stay active. Any other value is accepted rather than failing the session, but is enforced as `disable`: the key is only present to restrict something, so a mode this runtime cannot interpret fails closed to the most restrictive one it knows. Omit the key entirely to impose no restriction. */ @JsonProperty("disableBypassPermissionsMode") String disableBypassPermissionsMode, + /** When true, prevents Assisted Permissions from being activated. An actively Assisted session falls back to Manual Approval while the policy is in force. Omit the key or set it to false to impose no restriction. */ + @JsonProperty("disableAssistedPermissionsMode") Boolean disableAssistedPermissionsMode, /** Permission rules that block matching operations. Deny has highest precedence. */ @JsonProperty("deny") List deny, /** Permission rules that require explicit human approval. */ @JsonProperty("ask") List ask, /** Permission rules that allow matching operations unless another managed source, deny, or ask rule restricts them. */ - @JsonProperty("allow") List allow + @JsonProperty("allow") List allow, + /** Closed-world host boundary expressed as `Domain(hostname)`, `Domain(IP)`, or `Domain(*.example.com)` rules. Schemes, ports, paths, queries, and fragments are rejected because every network request must be enforceable at host-level egress. Multiple managed sources intersect their lists; an empty list denies all hosts. */ + @JsonProperty("limitTo") List limitTo ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsApi.java index adf8568aa2..e2e4a67fe3 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsApi.java @@ -29,7 +29,7 @@ public final class SessionManagedSettingsApi { } /** - * Identifies the target session. + * Waits for the live session's in-flight managed-settings application, then returns the retained effective snapshot used by runtime enforcement and by `session.managed_settings_resolved`. It does not perform another account, device, or server resolution, and rejects when resolution has not produced a snapshot. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java index faf08c57d6..cdd674ab24 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; import java.util.List; import javax.annotation.processing.Generated; @@ -25,6 +26,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record SessionManagedSettingsGetResult( + /** Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. */ @JsonProperty("source") ManagedSettingsResolvedSource source, /** Whether the server (account/org) managed-settings layer was present */ @@ -35,11 +38,11 @@ public record SessionManagedSettingsGetResult( @JsonProperty("clientManaged") Boolean clientManaged, /** Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. */ @JsonProperty("policyHelperManaged") Boolean policyHelperManaged, - /** Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. */ + /** Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. */ @JsonProperty("failClosed") Boolean failClosed, /** Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. */ @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, - /** Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. */ + /** Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. */ @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, /** Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. */ @JsonProperty("permissionsAllowIntersected") Boolean permissionsAllowIntersected, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpApi.java index 4960d36f02..5f805354c4 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpApi.java @@ -48,7 +48,23 @@ public final class SessionMcpApi { } /** - * Identifies the target session. + * Records the IDE the host is connected to, so the agent's system prompt can name it and its workspace folder. Null or an omitted `ide` clears the recorded value, which is how a host reports that it is disconnected; there is no separate clear method. Both `ideName` and `workspaceFolder` are required together, because half a state cannot be attributed to a project. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture setConnectedIdeInfo(SessionMcpSetConnectedIdeInfoParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.mcp.setConnectedIdeInfo", _p, Void.class); + } + + /** + * Lists materialized MCP servers and their connection status. Cache misses may start and wait for MCP servers. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -59,7 +75,18 @@ public CompletableFuture list() { } /** - * Server name whose tool list should be returned. + * Lists effective MCP configuration without starting, restarting, authenticating, or waiting for servers. An optional live observation is from an already materialized matching server; this is not a readiness guarantee. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture listConfigured() { + return caller.invoke("session.mcp.listConfigured", java.util.Map.of("sessionId", this.sessionId), SessionMcpListConfiguredResult.class); + } + + /** + * Lists the tools exposed by a connected MCP server on this session's host. This performs a live `tools/list` request. Tool UI metadata is returned independently of whether MCP Apps rendering is enabled for the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -75,7 +102,7 @@ public CompletableFuture listTools(SessionMcpListTool } /** - * Name of the MCP server to enable for the session. + * Enables an MCP server for the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -91,7 +118,7 @@ public CompletableFuture enable(SessionMcpEnableParams params) { } /** - * Name of the MCP server to enable for the session. + * Enables an MCP server for the session. *

* Accepts the extensible request, including inputs added after the params record. * @@ -106,7 +133,7 @@ public CompletableFuture enable(SessionMcpEnableRequest request) { } /** - * Name of the MCP server to disable for the session. + * Disables an MCP server for the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -122,7 +149,7 @@ public CompletableFuture disable(SessionMcpDisableParams params) { } /** - * Name of the MCP server to disable for the session. + * Disables an MCP server for the session. *

* Accepts the extensible request, including inputs added after the params record. * @@ -137,7 +164,7 @@ public CompletableFuture disable(SessionMcpDisableRequest request) { } /** - * Identifies the target session. + * Reloads MCP server connections for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -148,7 +175,7 @@ public CompletableFuture reload() { } /** - * Identifies the target session. + * Releases any turns waiting on an in-flight MCP load without cancelling the load, letting the agent proceed while MCP servers finish connecting in the background. No-op when no MCP load is in flight or waiting turns were already released. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -159,7 +186,7 @@ public CompletableFuture moveLoadingToB } /** - * Opaque MCP reload configuration. + * Reloads MCP server connections for the session with an explicit host-provided configuration. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -175,7 +202,7 @@ CompletableFuture reloadWithConfig(SessionMcpReloadWithCo } /** - * Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. + * Runs an MCP sampling inference on behalf of an MCP server. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -191,7 +218,7 @@ public CompletableFuture executeSampling(Sessio } /** - * The requestId previously passed to executeSampling that should be cancelled. + * Cancels an in-flight MCP sampling execution by request ID. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -207,7 +234,7 @@ public CompletableFuture cancelSampling } /** - * Mode controlling how MCP server env values are resolved (`direct` or `indirect`). + * Sets how environment-variable values supplied to MCP servers are resolved (direct or indirect). *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -223,7 +250,7 @@ public CompletableFuture setEnvValueMode(Sessio } /** - * Identifies the target session. + * Removes the auto-managed `github` MCP server when present. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -234,7 +261,7 @@ public CompletableFuture removeGitHub() { } /** - * Credential-free authentication identity used to configure GitHub MCP. + * Configures the built-in GitHub MCP server for the session's current auth context. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -250,7 +277,7 @@ CompletableFuture configureGitHub(SessionMcpConfigureG } /** - * Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. + * Starts an individual MCP server on the live session. Omit `config` for a config-free start-by-name of an already-configured server (reuses the server's already-registered configuration); supply `config` to start from a caller-supplied configuration. Session-scoped and ephemeral: the server is added to this session's running set only and is reaped when the session ends. Does NOT modify persistent user configuration (`mcp.config.*`), so it does not affect future sessions. The server surfaces through `session.mcp.list` and the `session.mcp_servers_loaded` / `session.mcp_server_status_changed` events like any other server. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -266,7 +293,7 @@ public CompletableFuture startServer(SessionMcpStartServerParams params) { } /** - * Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. + * Starts an individual MCP server on the live session. Omit `config` for a config-free start-by-name of an already-configured server (reuses the server's already-registered configuration); supply `config` to start from a caller-supplied configuration. Session-scoped and ephemeral: the server is added to this session's running set only and is reaped when the session ends. Does NOT modify persistent user configuration (`mcp.config.*`), so it does not affect future sessions. The server surfaces through `session.mcp.list` and the `session.mcp_servers_loaded` / `session.mcp_server_status_changed` events like any other server. *

* Accepts the extensible request, including inputs added after the params record. * @@ -281,7 +308,7 @@ public CompletableFuture startServer(SessionMcpStartServerRequest request) } /** - * Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. + * Restarts an individual MCP server on the live session (stops then starts). Omit `config` for a config-free restart-by-name of an already-configured server; supply `config` to restart with a replacement configuration. Session-scoped and ephemeral: does NOT modify persistent user configuration (`mcp.config.*`). *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -297,7 +324,7 @@ public CompletableFuture restartServer(SessionMcpRestartServerParams param } /** - * Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. + * Restarts an individual MCP server on the live session (stops then starts). Omit `config` for a config-free restart-by-name of an already-configured server; supply `config` to restart with a replacement configuration. Session-scoped and ephemeral: does NOT modify persistent user configuration (`mcp.config.*`). *

* Accepts the extensible request, including inputs added after the params record. * @@ -312,7 +339,7 @@ public CompletableFuture restartServer(SessionMcpRestartServerRequest requ } /** - * Server name for an individual MCP server stop. + * Stops an individual MCP server on the session's host. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -328,7 +355,7 @@ public CompletableFuture stopServer(SessionMcpStopServerParams params) { } /** - * Server name for an individual MCP server stop. + * Stops an individual MCP server on the session's host. *

* Accepts the extensible request, including inputs added after the params record. * @@ -343,7 +370,7 @@ public CompletableFuture stopServer(SessionMcpStopServerRequest request) { } /** - * Registration parameters for an external MCP client. + * Registers a pre-connected external MCP client (e.g. IDE) on the session's host. The caller retains lifecycle ownership of the client and transport. Marked internal because the `client` and `transport` arguments are in-process MCP SDK instances that cannot be serialized across the JSON-RPC boundary; once the CLI moves on top of the SDK, external clients will be expressed as transport configs the runtime can construct itself. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -359,7 +386,7 @@ CompletableFuture registerExternalClient(SessionMcpRegisterExternalClientP } /** - * Server name identifying the external client to remove. + * Unregisters a previously registered external MCP client by server name. Marked internal as the paired companion of `registerExternalClient`: only in-process callers that registered a client this way can meaningfully unregister it. Disappears alongside `registerExternalClient`: once external clients are described to the runtime as config rather than handed in as instances, lifecycle (including deregistration) is owned entirely by the runtime. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -375,7 +402,7 @@ CompletableFuture unregisterExternalClient(SessionMcpUnregisterExternalCli } /** - * Server name to check running status for. + * Checks whether a named MCP server is currently running on the session's host. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpAppsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpAppsApi.java index 6b932855b2..35cd4c57a3 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpAppsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpAppsApi.java @@ -32,7 +32,7 @@ public final class SessionMcpAppsApi { } /** - * MCP server and resource URI to fetch. + * Fetch an MCP resource (typically a `ui://` MCP App bundle, per SEP-1865) from a connected server. Requires the `mcp-apps` session capability. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -48,7 +48,7 @@ public CompletableFuture readResource(SessionM } /** - * MCP server to list app-callable tools for. + * List tools that an MCP App view is allowed to call (SEP-1865 visibility filter). Returns tools whose `_meta.ui.visibility` is unset (default `["model","app"]`) or includes `"app"`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -64,7 +64,7 @@ public CompletableFuture listTools(SessionMcpApps } /** - * MCP server, tool name, and arguments to invoke from an MCP App view. + * 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 `CallToolResult`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -80,7 +80,7 @@ public CompletableFuture callTool(SessionMcpAppsCallToolParams params) } /** - * Host context to advertise to MCP App guests. + * Replace the host context returned to MCP App guests on `ui/initialize`. Hosts use this to advertise theme, locale, or other metadata to the guest UI. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -96,7 +96,7 @@ public CompletableFuture setHostContext(SessionMcpAppsSetHostContextParams } /** - * Identifies the target session. + * Read the current host context advertised to MCP App guests. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -107,7 +107,7 @@ public CompletableFuture getHostContext() { } /** - * MCP server to diagnose MCP Apps wiring for. + * Diagnose MCP Apps wiring for a specific MCP server. Reports the session capability, feature-flag state, advertised extension, and how many tools have `_meta.ui` populated. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java index 54950ec4f4..7978c03553 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java @@ -31,6 +31,7 @@ public record SessionMcpExecuteSamplingParams( /** Name of the MCP server that initiated the sampling request */ @JsonProperty("serverName") String serverName, /** 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). */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("mcpRequestId") Object 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. */ @JsonProperty("request") McpExecuteSamplingRequest request diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpHeadersApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpHeadersApi.java index 45679f83a4..b6c940462e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpHeadersApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpHeadersApi.java @@ -31,7 +31,7 @@ public final class SessionMcpHeadersApi { } /** - * MCP headers refresh request id and the host response. + * Responds to a pending MCP dynamic headers refresh request. Hosts that subscribe to `mcp.headers_refresh_required` use this to provide short-lived per-server headers or to indicate that no dynamic headers are available for this refresh. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpListConfiguredParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpListConfiguredParams.java new file mode 100644 index 0000000000..d4d886b5b0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpListConfiguredParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the target session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpListConfiguredParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpListConfiguredResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpListConfiguredResult.java new file mode 100644 index 0000000000..b54b5b238c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpListConfiguredResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Effective MCP configuration with optional live observations from matching already materialized servers. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionMcpListConfiguredResult( + /** Effective configured MCP servers. */ + @JsonProperty("servers") List servers +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java index 8e90316975..3910d287eb 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java @@ -32,7 +32,7 @@ public final class SessionMcpOauthApi { } /** - * Pending MCP OAuth request ID and host-provided token or cancellation response. + * Resolves a pending MCP OAuth request with a host-provided token or cancellation. The pending request is emitted as mcp.oauth_required with the data necessary to authorize the request. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -48,7 +48,7 @@ public CompletableFuture handlePendin } /** - * Identifies the MCP server whose persisted OAuth credentials were updated. + * Notifies the session that MCP OAuth authentication succeeded and updated credentials were persisted, so cached tool definitions can be refreshed. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -64,7 +64,7 @@ public CompletableFuture authenticationStateChanged(SessionMcpOauthAuthent } /** - * Effect-free preparation bound to the existing local session, requester and installation, with frozen options. + * Prepares an inert, expiring owned OAuth login bound to the original session requester and exact installation. Does not activate, connect, read credentials or open a browser. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -80,7 +80,7 @@ public CompletableFuture prepareLogin(Session } /** - * Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. + * Starts OAuth authentication for a remote MCP server. Owned servers require the original one-use prepareLogin handle and exact installation ID; manual servers retain the existing direct login behaviour. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -96,7 +96,7 @@ public CompletableFuture login(SessionMcpOauthLoginP } /** - * Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. + * Starts OAuth authentication for a remote MCP server. Owned servers require the original one-use prepareLogin handle and exact installation ID; manual servers retain the existing direct login behaviour. *

* Accepts the extensible request, including inputs added after the params record. * @@ -111,7 +111,7 @@ public CompletableFuture login(SessionMcpOauthLoginR } /** - * Host-delivered callback for a runtime-managed MCP OAuth login. + * Completes a runtime-managed MCP OAuth login after the authorization server redirects to a host-managed callback URL. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -127,7 +127,7 @@ public CompletableFuture complete(SessionMcpOauthCompleteParams params) { } /** - * Remote MCP server name for a passive OAuth status probe. + * Passively probes a configured remote MCP server to classify whether OAuth is required or a cached/override token is accepted. Does not start OAuth, emit pending OAuth requests, or mutate MCP connection state. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -143,7 +143,7 @@ public CompletableFuture probe(SessionMcpOauthProbeParams p } /** - * Remote MCP server name for a passive OAuth status probe. + * Passively probes a configured remote MCP server to classify whether OAuth is required or a cached/override token is accepted. Does not start OAuth, emit pending OAuth requests, or mutate MCP connection state. *

* Accepts the extensible request, including inputs added after the params record. * @@ -158,7 +158,7 @@ public CompletableFuture probe(SessionMcpOauthProbeRequest } /** - * Targets only the original prepared/applying owned login on this exact session requester. + * Cancels the exact owned OAuth login issued to this original session requester, without clearing shared credentials. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -174,7 +174,7 @@ public CompletableFuture cancelLogin(SessionMc } /** - * Pending MCP OAuth request id to respond to. + * Responds to a pending MCP OAuth authorization request by its request id. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpPromptsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpPromptsApi.java index 7b47b74a21..ec60f552ca 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpPromptsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpPromptsApi.java @@ -31,7 +31,7 @@ public final class SessionMcpPromptsApi { } /** - * MCP server whose prompts to enumerate. + * Enumerate one page of prompts a connected MCP server exposes (proxies MCP `prompts/list`). Pass `cursor` to continue from a prior result's `nextCursor`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture list(SessionMcpPromptsList } /** - * MCP server, prompt name, and optional string-valued arguments. + * Get a prompt's messages from a connected MCP server (proxies MCP `prompts/get`). Content is preserved as opaque JSON. Does not send messages to the model, execute tools, or fetch referenced resources. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpResourcesApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpResourcesApi.java index c1a30e135d..e81f50eb80 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpResourcesApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpResourcesApi.java @@ -31,7 +31,7 @@ public final class SessionMcpResourcesApi { } /** - * MCP server and resource URI to fetch. + * Fetch an MCP resource from a connected server by URI (proxies MCP `resources/read`). *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture read(SessionMcpResources } /** - * MCP server whose resources to enumerate. + * Enumerate one page of resources a connected MCP server exposes (proxies MCP `resources/list`). Pass `cursor` to continue from a prior result's `nextCursor`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -63,7 +63,7 @@ public CompletableFuture list(SessionMcpResources } /** - * MCP server whose resource templates to enumerate. + * Enumerate one page of resource templates a connected MCP server exposes (proxies MCP `resources/templates/list`). Pass `cursor` to continue from a prior result's `nextCursor`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpSetConnectedIdeInfoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpSetConnectedIdeInfoParams.java new file mode 100644 index 0000000000..38e53b55d6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpSetConnectedIdeInfoParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Records which IDE the host is connected to, or clears it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionMcpSetConnectedIdeInfoParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports that it is disconnected. */ + @JsonProperty("ide") SessionConnectedIdeInfo ide +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataApi.java index 8d7f3dd753..bf97a0ec39 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataApi.java @@ -31,7 +31,7 @@ public final class SessionMetadataApi { } /** - * Identifies the target session. + * Returns a snapshot of the session's identifying metadata, mode, agent, and remote info. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture snapshot() { } /** - * Identifies the target session. + * Returns the client-owned string metadata persisted with this local session. The metadata is not included in model context, events, telemetry, snapshots, or remote exports. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -53,7 +53,7 @@ public CompletableFuture getClientMetadata() { } /** - * Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes. + * Atomically patches the client-owned string metadata persisted with this local session and returns the committed bag. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -69,7 +69,7 @@ public CompletableFuture updateClientMetadata(SessionMetadataUpd } /** - * Identifies the target session. + * Reports whether the local session is currently processing user/agent messages. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -80,7 +80,7 @@ public CompletableFuture isProcessing() { } /** - * Identifies the target session. + * Returns a snapshot of activity flags for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -91,7 +91,7 @@ public CompletableFuture activity() { } /** - * Model identifier and token limits used to compute the context-info breakdown. + * Returns the token breakdown for the session's current context window for a given model. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -107,7 +107,7 @@ public CompletableFuture contextInfo(SessionMe } /** - * Identifies the target session. + * Returns the experimental per-source attribution breakdown of the session's current context window as a flat list of entries (skills, subagents, MCP servers, built-in tools, plugin rollups, system/tool-definition costs, with nesting via parentId), plus the successful compaction count. The heaviest individual messages are available separately via `metadata.getContextHeaviestMessages`. Returns null until the session has initialized its system prompt and tool metadata. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -118,7 +118,7 @@ public CompletableFuture getContextA } /** - * Parameters for the heaviest-messages query. + * Returns the largest individual messages currently in the session's context window, most-expensive first. Companion to `metadata.getContextAttribution`. Returns an empty list until the session has initialized. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -134,7 +134,7 @@ public CompletableFuture getCon } /** - * Updated working-directory/git context to record on the session. + * Records a working-directory/git context change and emits a `session.context_changed` event. For a local session, a report whose `cwd` diverges from the session's current working directory is ignored (the call still succeeds but records nothing and emits no event): a local session's working directory is authoritative and is moved via `metadata.setWorkingDirectory` (or an SDK `session.resume` that supplies a `workingDirectory`), not by this method. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -150,7 +150,7 @@ public CompletableFuture recordContextChange(SessionMetadataRecordContextC } /** - * Absolute path to set as the session's new working directory. For local sessions the path must be absolute and exist on disk: it is validated before any session state changes, and a failing validation rejects the call with nothing mutated, persisted, or emitted. Remote sessions record the path as-is. + * Updates the session's working directory. For local sessions the target is validated first (an absolute path that exists on disk) and the permission primary directory is re-based; a rejected validation fails the call before any session state changes. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -166,7 +166,7 @@ public CompletableFuture setWorkingDir } /** - * Model identifier to use when re-tokenizing the session's existing messages. + * Re-tokenizes the session's existing messages against a model and returns aggregate token totals. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoParams.java index 0c5b909db7..a190c0d194 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoParams.java @@ -26,11 +26,13 @@ public record SessionMetadataContextInfoParams( /** Target session identifier */ @JsonProperty("sessionId") String sessionId, - /** Maximum prompt tokens allowed by the target model. Pass 0 to use the runtime default. */ + /** Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from the session. */ @JsonProperty("promptTokenLimit") Long promptTokenLimit, - /** Maximum output tokens allowed by the target model. Pass 0 if unknown. */ + /** Requested output allowance to reserve against the combined context ceiling. Pass 0 to resolve the session's request cap, falling back to the model's advertised output limit. */ @JsonProperty("outputTokenLimit") Long outputTokenLimit, /** Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. */ - @JsonProperty("selectedModel") String selectedModel + @JsonProperty("selectedModel") String selectedModel, + /** Provider owning selectedModel. Omit to use the current provider for the current model, or deterministic legacy lookup for a different model. */ + @JsonProperty("providerId") String providerId ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoResult.java index 6472956026..4415e14096 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataContextInfoResult.java @@ -34,6 +34,10 @@ public record SessionMetadataContextInfoResult( public record SessionMetadataContextInfoResultContextInfo( /** The model used for token counting */ @JsonProperty("modelName") String modelName, + /** Provider whose catalog supplies this context window. Omitted when provider identity is unavailable. */ + @JsonProperty("provider") ModelProviderRef provider, + /** Provider-owned model display label, or the Auto routing label. Presentation only; modelName remains the tokenization identity. */ + @JsonProperty("displayModelName") String displayModelName, /** Tokens consumed by the system prompt */ @JsonProperty("systemTokens") Long systemTokens, /** Tokens consumed by user/assistant/tool messages */ @@ -44,13 +48,13 @@ public record SessionMetadataContextInfoResultContextInfo( @JsonProperty("mcpToolsTokens") Long mcpToolsTokens, /** Sum of system, conversation and tool-definition tokens */ @JsonProperty("totalTokens") Long totalTokens, - /** Maximum prompt tokens allowed by the model (or DEFAULT_TOKEN_LIMIT if unspecified) */ + /** Effective input budget: the selected tier's prompt allowance bounded by the combined context ceiling minus the requested output allowance. Uses DEFAULT_TOKEN_LIMIT when limits are unspecified. */ @JsonProperty("promptTokenLimit") Long promptTokenLimit, /** Token count at which background compaction starts (configurable percentage of promptTokenLimit) */ @JsonProperty("compactionThreshold") Long compactionThreshold, - /** Prompt token limit plus the model's full output token limit. */ + /** Advertised prompt allowance for the selected context tier, without adding output tokens. The denominator for context-usage displays. */ @JsonProperty("limit") Long limit, - /** Output reserve plus tokens after the buffer-exhaustion blocking threshold (default 95%) */ + /** Output reservation overlapping the displayed prompt allowance plus tokens after the effective input budget's buffer-exhaustion blocking threshold (default 95%). */ @JsonProperty("bufferTokens") Long bufferTokens ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataGetContextAttributionResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataGetContextAttributionResult.java index c27f37afb0..44713111cf 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataGetContextAttributionResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMetadataGetContextAttributionResult.java @@ -40,11 +40,11 @@ public record SessionMetadataGetContextAttributionResultContextAttribution( @JsonProperty("modelId") String modelId, /** How `modelId` was chosen. Not a closed set — tolerate unknown values. Known values today: `autoResolved` (the model Auto resolved to), `selected` (the user's explicitly selected model), `default` (a fallback before any model is known). */ @JsonProperty("modelSource") String modelSource, - /** Maximum prompt tokens the resolved model accepts — the denominator for a `##k/###k` context-usage display. Mirrors `SessionContextInfo.promptTokenLimit`. */ + /** Effective input budget after reserving requested output against the combined context ceiling. Mirrors `SessionContextInfo.promptTokenLimit`. */ @JsonProperty("promptTokenLimit") Long promptTokenLimit, - /** Prompt limit plus the model's output reserve: the full context window `categories.freeSpace` and `categories.buffer` are measured against. Mirrors `SessionContextInfo.limit`. */ + /** Advertised prompt allowance for the selected context tier: the denominator for context-usage displays and capacity for `categories.freeSpace` and `categories.buffer`. Mirrors `SessionContextInfo.limit`. */ @JsonProperty("limit") Long limit, - /** Output reserve plus the tokens past the buffer-exhaustion blocking threshold. Mirrors `SessionContextInfo.bufferTokens`. */ + /** Output reservation overlapping the displayed prompt allowance plus the tokens past the effective input budget's buffer-exhaustion blocking threshold. Mirrors `SessionContextInfo.bufferTokens`. */ @JsonProperty("bufferTokens") Long bufferTokens, /** Token count at which background compaction starts. Mirrors `SessionContextInfo.compactionThreshold`. */ @JsonProperty("compactionThreshold") Long compactionThreshold, @@ -72,7 +72,7 @@ public record SessionMetadataGetContextAttributionResultContextAttributionCatego @JsonProperty("messages") Long messages, /** Remaining unused window capacity (clamped at 0). */ @JsonProperty("freeSpace") Long freeSpace, - /** Output reserve plus post-blocking-threshold buffer. */ + /** Overlapping output reservation plus post-blocking-threshold buffer. */ @JsonProperty("buffer") Long buffer ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeApi.java index 0f4989a920..8c2c2d66da 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeApi.java @@ -31,7 +31,7 @@ public final class SessionModeApi { } /** - * Identifies the target session. + * Gets the current agent interaction mode. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture get() { } /** - * Agent interaction mode to apply to the session. + * Sets the current agent interaction mode. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeSetParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeSetParams.java index 9a20862a13..9c11577700 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeSetParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModeSetParams.java @@ -36,6 +36,8 @@ public record SessionModeSetParams( @JsonProperty("planModelConfigured") Boolean planModelConfigured, /** Dedicated model to use in plan mode, when configured. */ @JsonProperty("planModel") String planModel, + /** Provider owning planModel. Omit for legacy bare-model selection. */ + @JsonProperty("planModelProviderId") String planModelProviderId, /** Reasoning effort to use with the dedicated plan model. */ @JsonProperty("planReasoningEffort") String planReasoningEffort, /** Context tier to use with the dedicated plan model. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java index 8d47c9c716..bfd5d8a89e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -31,7 +32,7 @@ public final class SessionModelApi { } /** - * Identifies the target session. + * Gets the session's authoritative model snapshot, including the committed Auto preference and any newer unclaimed Auto preference waiting for a future user turn. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +43,7 @@ public CompletableFuture getCurrent() { } /** - * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. + * Switches the session to a model and optional reasoning configuration. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +59,22 @@ public CompletableFuture switchTo(SessionModelSwitch } /** - * An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`. + * Switches the session to a model and optional reasoning configuration. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture switchTo(SessionModelSwitchToRequest request) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(Objects.requireNonNull(request, "request")); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.model.switchTo", _p, SessionModelSwitchToResult.class); + } + + /** + * Requests an Auto preference change without changing the session's selected model. The latest unclaimed request wins; the runtime commits it only after a later prompt using the `auto` model mints a usable model and token pair. A `pending` response confirms that the request was accepted, not that it committed. Observe eventual success through `session.model_change`, failure through the ephemeral `session.auto_tier_switch_failed` event, or current unclaimed state through `session.model.getCurrent`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -74,7 +90,7 @@ public CompletableFuture switchAutoTier(Sessio } /** - * Managed, repository, and CLI model overrides to overlay onto the session at startup. + * Resolves and applies organization-managed and repository model overlays. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -90,7 +106,23 @@ CompletableFuture applyStartupOverlay(SessionModelApplyStar } /** - * Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error. + * Clears an unchanged startup model/provider seed before default-model resolution. Never clears a resumed or user-selected model. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture clearStartupSeed(SessionModelClearStartupSeedParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.model.clearStartupSeed", _p, ModelClearStartupSeedResult.class); + } + + /** + * Replaces or clears the host-supplied model allowlist for a running session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -106,7 +138,7 @@ public CompletableFuture setAllowedModels(Se } /** - * Reasoning effort level to apply to the currently selected model. + * Updates the session's reasoning effort without changing the selected model. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -122,7 +154,23 @@ public CompletableFuture setReasoningEffor } /** - * Optional listing options. + * Computes whether the session's current model shows reasoning summaries and how a host should present them: the default Ctrl+T visibility, reasoning headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is redundant. The runtime folds in the session's model catalog, selection and reasoning-summaries experiment assignment; the host supplies only its own persisted setting and current visibility. This method reads the session's resolved model catalog rather than resolving it, so call `session.model.list` first on a session that has not listed models or run a turn; until then the result is `ready: false`. A session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider, never caches one and stays `ready: false`. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getReasoningSummaries(SessionModelGetReasoningSummariesParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.model.getReasoningSummaries", _p, SessionModelGetReasoningSummariesResult.class); + } + + /** + * Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's. *

* Invokes the method with no params, applying the runtime defaults. * @@ -135,7 +183,7 @@ public CompletableFuture list() { } /** - * Optional listing options. + * Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApplyStartupOverlayParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApplyStartupOverlayParams.java index ad25a718a2..e4aadb58f1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApplyStartupOverlayParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApplyStartupOverlayParams.java @@ -36,6 +36,8 @@ record SessionModelApplyStartupOverlayParams( @JsonProperty("autoTier") AutoTier autoTier, /** Model selected by repository settings, when configured. */ @JsonProperty("repoModel") String repoModel, + /** Provider owning the repository-selected model. Omitted repository provider identity retains legacy bare-model behavior. */ + @JsonProperty("repoModelProviderId") String repoModelProviderId, /** Reasoning effort selected by repository settings, when configured. */ @JsonProperty("repoReasoningEffort") String repoReasoningEffort, /** Context tier selected by repository settings, when configured. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelClearStartupSeedParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelClearStartupSeedParams.java new file mode 100644 index 0000000000..d927c746ca --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelClearStartupSeedParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.model.clearStartupSeed} RPC method. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionModelClearStartupSeedParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + @JsonProperty("expectedModel") String expectedModel, + /** Provider captured with the startup seed; omission matches only an unqualified seed. */ + @JsonProperty("expectedProviderId") String expectedProviderId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java index 6d6e79a26a..28ef368715 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java @@ -26,8 +26,12 @@ public record SessionModelGetCurrentResult( /** Currently active model identifier */ @JsonProperty("modelId") String modelId, + /** Provider selected for this model. Together with modelId, identifies a catalog entry even when providers serve the same model. Omitted for unattributed legacy selections. */ + @JsonProperty("providerId") String providerId, /** Captured base model to restore when leaving plan mode. Omitted outside plan mode or when no plan override has captured a base model. Persistent agent model requirements apply to this model rather than the temporary plan model. */ @JsonProperty("planBaseModelId") String planBaseModelId, + /** Provider of planBaseModelId, when that saved selection is provider-qualified. */ + @JsonProperty("planBaseProviderId") String planBaseProviderId, /** Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. */ @JsonProperty("reasoningEffort") String reasoningEffort, /** Context tier for models that support multiple context-window sizes. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesParams.java new file mode 100644 index 0000000000..488fe67616 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesParams.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Host presentation state the reasoning-summaries policy depends on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelGetReasoningSummariesParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** The host's persisted `showReasoning` user setting, omitted when unset. */ + @JsonProperty("persistedShowReasoning") Boolean persistedShowReasoning, + /** Whether the host is currently showing reasoning summaries. Defaults to false. */ + @JsonProperty("summariesVisible") Boolean summariesVisible +) { + + /** + * Creates host presentation state; the session-scoped wrapper supplies the session ID. + * + * @param persistedShowReasoning the persisted visibility setting, or null when unset + * @param summariesVisible whether summaries are visible, or null for the default + */ + public SessionModelGetReasoningSummariesParams(Boolean persistedShowReasoning, Boolean summariesVisible) { + this(null, persistedShowReasoning, summariesVisible); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesResult.java new file mode 100644 index 0000000000..c23a1af9ea --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesResult.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Reasoning-summaries presentation policy for the session's current model. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelGetReasoningSummariesResult( + /** False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. */ + @JsonProperty("ready") Boolean ready, + /** Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. */ + @JsonProperty("experimentSettled") Boolean experimentSettled, + /** Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. */ + @JsonProperty("sessionShowsSummaries") Boolean sessionShowsSummaries, + /** Whether the selected model shows reasoning summaries by default. */ + @JsonProperty("modelDefaultShowsSummaries") Boolean modelDefaultShowsSummaries, + /** Whether the selected model emits reasoning headers. */ + @JsonProperty("showReasoningHeaders") Boolean showReasoningHeaders, + /** Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. */ + @JsonProperty("visibility") Boolean visibility, + /** Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. */ + @JsonProperty("showHiddenHint") Boolean showHiddenHint, + /** Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. */ + @JsonProperty("clearRedundantSetting") Boolean clearRedundantSetting +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelListResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelListResult.java index 1c73b4b22f..3a18d77488 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelListResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelListResult.java @@ -33,6 +33,8 @@ public record SessionModelListResult( /** Cost categories for the full CAPI catalog, including picker-disabled models that Auto may select. Metadata only; entries absent from `list` are not manually selectable. */ @JsonProperty("modelPriceCategories") List modelPriceCategories, /** Per-quota snapshots returned alongside the model list, keyed by quota type. */ - @JsonProperty("quotaSnapshots") Map quotaSnapshots + @JsonProperty("quotaSnapshots") Map quotaSnapshots, + /** Ordered Auto routing preferences discovered for this session's account. */ + @JsonProperty("auto") AutoTierMetadata auto ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java index a37eebd2f6..0f30a514ca 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java @@ -26,7 +26,7 @@ public record SessionModelSwitchToParams( /** Target session identifier */ @JsonProperty("sessionId") String sessionId, - /** Model selection id to switch to, as returned by `list`. A bare id (e.g. `claude-sonnet-4.6`) names a Copilot (CAPI) model; a provider-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a registry BYOK model. */ + /** Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. */ @JsonProperty("modelId") String modelId, /** Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. */ @JsonProperty("autoTier") AutoTier autoTier, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToRequest.java new file mode 100644 index 0000000000..09168fcb52 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToRequest.java @@ -0,0 +1,410 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class SessionModelSwitchToRequest { + + /** Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. */ + @JsonProperty("modelId") + private final String modelId; + + /** Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. */ + @JsonProperty("autoTier") + private AutoTier autoTier; + + /** Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. */ + @JsonProperty("reasoningEffort") + private String reasoningEffort; + + /** Reasoning summary mode to request for supported model clients */ + @JsonProperty("reasoningSummary") + private ReasoningSummary reasoningSummary; + + /** Output verbosity level to request for supported models */ + @JsonProperty("verbosity") + private Verbosity verbosity; + + /** Override individual model capabilities resolved by the runtime */ + @JsonProperty("modelCapabilities") + private ModelCapabilitiesOverride modelCapabilities; + + /** 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. */ + @JsonProperty("contextTier") + private ContextTier contextTier; + + /** Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. */ + @JsonProperty("source") + private ModelChangeSource source; + + /** When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). */ + @JsonProperty("deferIfModelChangeQueued") + private Boolean deferIfModelChangeQueued; + + /** Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. */ + @JsonProperty("compactionDecision") + private String compactionDecision; + + /** When true, evaluate context-window compaction policy before applying the switch. */ + @JsonProperty("runCompactionPreflight") + private Boolean runCompactionPreflight; + + /** Optional repository settings scope to persist after the switch commits. */ + @JsonProperty("repoScope") + private String repoScope; + + /** Settings scope used when persisting the selected model. */ + @JsonProperty("modelChangeScope") + private String modelChangeScope; + + /** Require the target to be currently available and enabled before applying the switch. */ + @JsonProperty("requireAvailable") + private Boolean requireAvailable; + + /** Optional settings context and explicit-override flags used to persist a picker selection. */ + @JsonProperty("pickerPersistence") + private ModelPickerPersistenceRequest pickerPersistence; + + /** Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. */ + @JsonProperty("providerId") + private String providerId; + + /** + * Creates a request with its required inputs. + * + * @param modelId Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. + */ + public SessionModelSwitchToRequest(String modelId) { + this.modelId = Objects.requireNonNull(modelId, "modelId"); + } + + /** + * Returns the {@code modelId} property. + * + * @return Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. + */ + public String getModelId() { + return modelId; + } + + /** + * Returns the {@code autoTier} property. + * + * @return Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. + */ + public AutoTier getAutoTier() { + return autoTier; + } + + /** + * Returns the {@code reasoningEffort} property. + * + * @return Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. + */ + public String getReasoningEffort() { + return reasoningEffort; + } + + /** + * Returns the {@code reasoningSummary} property. + * + * @return Reasoning summary mode to request for supported model clients + */ + public ReasoningSummary getReasoningSummary() { + return reasoningSummary; + } + + /** + * Returns the {@code verbosity} property. + * + * @return Output verbosity level to request for supported models + */ + public Verbosity getVerbosity() { + return verbosity; + } + + /** + * Returns the {@code modelCapabilities} property. + * + * @return Override individual model capabilities resolved by the runtime + */ + public ModelCapabilitiesOverride getModelCapabilities() { + return modelCapabilities; + } + + /** + * Returns the {@code contextTier} property. + * + * @return 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. + */ + public ContextTier getContextTier() { + return contextTier; + } + + /** + * Returns the {@code source} property. + * + * @return Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. + */ + public ModelChangeSource getSource() { + return source; + } + + /** + * Returns the {@code deferIfModelChangeQueued} property. + * + * @return When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). + */ + public Boolean getDeferIfModelChangeQueued() { + return deferIfModelChangeQueued; + } + + /** + * Returns the {@code compactionDecision} property. + * + * @return Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. + */ + public String getCompactionDecision() { + return compactionDecision; + } + + /** + * Returns the {@code runCompactionPreflight} property. + * + * @return When true, evaluate context-window compaction policy before applying the switch. + */ + public Boolean getRunCompactionPreflight() { + return runCompactionPreflight; + } + + /** + * Returns the {@code repoScope} property. + * + * @return Optional repository settings scope to persist after the switch commits. + */ + public String getRepoScope() { + return repoScope; + } + + /** + * Returns the {@code modelChangeScope} property. + * + * @return Settings scope used when persisting the selected model. + */ + public String getModelChangeScope() { + return modelChangeScope; + } + + /** + * Returns the {@code requireAvailable} property. + * + * @return Require the target to be currently available and enabled before applying the switch. + */ + public Boolean getRequireAvailable() { + return requireAvailable; + } + + /** + * Returns the {@code pickerPersistence} property. + * + * @return Optional settings context and explicit-override flags used to persist a picker selection. + */ + public ModelPickerPersistenceRequest getPickerPersistence() { + return pickerPersistence; + } + + /** + * Returns the {@code providerId} property. + * + * @return Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. + */ + public String getProviderId() { + return providerId; + } + + /** + * Sets the {@code autoTier} property. + * + * @param value Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. + * @return this request + */ + public SessionModelSwitchToRequest setAutoTier(AutoTier value) { + this.autoTier = value; + return this; + } + + /** + * Sets the {@code reasoningEffort} property. + * + * @param value Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. + * @return this request + */ + public SessionModelSwitchToRequest setReasoningEffort(String value) { + this.reasoningEffort = value; + return this; + } + + /** + * Sets the {@code reasoningSummary} property. + * + * @param value Reasoning summary mode to request for supported model clients + * @return this request + */ + public SessionModelSwitchToRequest setReasoningSummary(ReasoningSummary value) { + this.reasoningSummary = value; + return this; + } + + /** + * Sets the {@code verbosity} property. + * + * @param value Output verbosity level to request for supported models + * @return this request + */ + public SessionModelSwitchToRequest setVerbosity(Verbosity value) { + this.verbosity = value; + return this; + } + + /** + * Sets the {@code modelCapabilities} property. + * + * @param value Override individual model capabilities resolved by the runtime + * @return this request + */ + public SessionModelSwitchToRequest setModelCapabilities(ModelCapabilitiesOverride value) { + this.modelCapabilities = value; + return this; + } + + /** + * Sets the {@code contextTier} property. + * + * @param value 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. + * @return this request + */ + public SessionModelSwitchToRequest setContextTier(ContextTier value) { + this.contextTier = value; + return this; + } + + /** + * Sets the {@code source} property. + * + * @param value Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. + * @return this request + */ + public SessionModelSwitchToRequest setSource(ModelChangeSource value) { + this.source = value; + return this; + } + + /** + * Sets the {@code deferIfModelChangeQueued} property. + * + * @param value When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). + * @return this request + */ + public SessionModelSwitchToRequest setDeferIfModelChangeQueued(Boolean value) { + this.deferIfModelChangeQueued = value; + return this; + } + + /** + * Sets the {@code compactionDecision} property. + * + * @param value Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. + * @return this request + */ + public SessionModelSwitchToRequest setCompactionDecision(String value) { + this.compactionDecision = value; + return this; + } + + /** + * Sets the {@code runCompactionPreflight} property. + * + * @param value When true, evaluate context-window compaction policy before applying the switch. + * @return this request + */ + public SessionModelSwitchToRequest setRunCompactionPreflight(Boolean value) { + this.runCompactionPreflight = value; + return this; + } + + /** + * Sets the {@code repoScope} property. + * + * @param value Optional repository settings scope to persist after the switch commits. + * @return this request + */ + public SessionModelSwitchToRequest setRepoScope(String value) { + this.repoScope = value; + return this; + } + + /** + * Sets the {@code modelChangeScope} property. + * + * @param value Settings scope used when persisting the selected model. + * @return this request + */ + public SessionModelSwitchToRequest setModelChangeScope(String value) { + this.modelChangeScope = value; + return this; + } + + /** + * Sets the {@code requireAvailable} property. + * + * @param value Require the target to be currently available and enabled before applying the switch. + * @return this request + */ + public SessionModelSwitchToRequest setRequireAvailable(Boolean value) { + this.requireAvailable = value; + return this; + } + + /** + * Sets the {@code pickerPersistence} property. + * + * @param value Optional settings context and explicit-override flags used to persist a picker selection. + * @return this request + */ + public SessionModelSwitchToRequest setPickerPersistence(ModelPickerPersistenceRequest value) { + this.pickerPersistence = value; + return this; + } + + /** + * Sets the {@code providerId} property. + * + * @param value Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. + * @return this request + */ + public SessionModelSwitchToRequest setProviderId(String value) { + this.providerId = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionNameApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionNameApi.java index 9bfc5bea59..aeefa0df31 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionNameApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionNameApi.java @@ -31,7 +31,7 @@ public final class SessionNameApi { } /** - * Identifies the target session. + * Gets the session's friendly name. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture get() { } /** - * New friendly name to apply to the session. + * Sets the session's friendly name. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +58,7 @@ public CompletableFuture set(SessionNameSetParams params) { } /** - * Auto-generated session summary to apply as the session's name when no user-set name exists. + * Persists an auto-generated session summary as the session's name when no user-set name exists. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java index dbb3080cdb..2ac3d57c97 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java @@ -49,6 +49,8 @@ public record SessionOpenOptions( @JsonProperty("expAssignments") Object expAssignments, /** Opt-in: self-fetch and enforce enterprise managed settings, including managed hook policies, at session bootstrap. */ @JsonProperty("enableManagedSettings") Boolean enableManagedSettings, + /** Opt in to enforcing non-overridable managed model controls on session model, Auto-tier, reasoning-effort, and context-tier changes. Managed defaults still apply when omitted; this option only turns conflicting changes into errors. */ + @JsonProperty("enforceManagedModelDefaults") Boolean enforceManagedModelDefaults, /** Permissions-only enterprise policy injected by the SDK host at session create or resume. Composes restrictively with self-fetched and device policy and is not persisted. */ @JsonProperty("managedSettings") SessionManagedSettings managedSettings, /** Opt in to capturing file changes for session rewind and session diff. Capture cannot reconstruct changes made before it was enabled. On create it starts capture from the first turn. It is also honored on resume: for a session that already has tracked prior turns, tracking continues automatically even if this is omitted; passing it on resume additionally enables tracking for an eligible session that has no prior root turn yet. Resuming a session whose prior root turns were never tracked has no restorable baseline, so tracking stays disabled for it and rewind reports file change tracking as unavailable; the resume itself still succeeds, so sessions that predate tracking remain loadable. The opt-in is only rejected when the session can never track (a subagent session, or one without local session storage). It is intentionally absent from the mutable options update because enabling it after edits have occurred would create an incomplete, misleading baseline. Subagents share the parent session's capture store and are not tracked as separate rewind points: a file a subagent writes is attributed to whichever root user turn was open when the capture was staged, just before the tool body ran. A turn cannot open while a staged capture is still in flight, so a subagent tool that staged under the spawning turn stays attributed to it however late the write lands, while a capture it stages after the user's next message belongs to that later turn. Attribution decides which turn's rewind point counts and file preview include that write; it does not narrow which rewinds revert it, because a rewind restores every capture from the selected turn onward, so the earlier spawning turn reverts it as well. */ @@ -63,6 +65,8 @@ public record SessionOpenOptions( @JsonProperty("provider") ProviderConfig provider, /** Options scoped to the built-in CAPI (Copilot API) provider. */ @JsonProperty("capi") CapiSessionOptions capi, + /** Whether a CLI host explicitly requested the initial Auto preference. False preserves a settings-derived preference without validating availability during creation; execution still validates it. Defaults to true and is ignored for non-CLI callers. */ + @JsonProperty("autoTierIsExplicit") Boolean autoTierIsExplicit, /** Named BYOK provider connections, additive to CAPI auth. Combining with `provider` is rejected. */ @JsonProperty("providers") List providers, /** BYOK model definitions added to the selectable model list, each referencing a provider name. */ @@ -113,11 +117,17 @@ public record SessionOpenOptions( @JsonProperty("managedMcpServers") Map managedMcpServers, /** Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. */ @JsonProperty("allowAllMcpServerInstructions") Boolean allowAllMcpServerInstructions, - /** Additional directories to search for skills. */ + /** Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ @JsonProperty("skillDirectories") List skillDirectories, + /** Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("agentDirectories") List agentDirectories, + /** Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("instructionDirectories") List instructionDirectories, + /** Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("hookDirectories") List hookDirectories, /** Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ @JsonProperty("ignoredSkillsLocations") List ignoredSkillsLocations, - /** Whether skill loading is enabled. When omitted, an SDK skill provider enables skills by default. */ + /** Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill provider enable skills independently of enableConfigDiscovery. */ @JsonProperty("enableSkills") Boolean enableSkills, /** Whether the requesting SDK session has a skill provider. The provider remains ephemeral and is never persisted in session options or history. When enableSkills is false, it remains bound but dormant and receives no callbacks. Cloud, relay, handoff, and raw sessions.open flows reject it because they cannot safely pre-register the callback handler. */ @JsonProperty("hasSkillProvider") Boolean hasSkillProvider, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsApi.java index 32d4b76908..06986da2ff 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsApi.java @@ -31,7 +31,7 @@ public final class SessionOptionsApi { } /** - * Patch of mutable session options to apply to the running session. + * Patches the genuinely-mutable subset of session options. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java index 3a30a13527..a5862263ae 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java @@ -82,8 +82,14 @@ public record SessionOptionsUpdateParams( @JsonProperty("envValueMode") OptionsUpdateEnvValueMode envValueMode, /** Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. */ @JsonProperty("allowAllMcpServerInstructions") Boolean allowAllMcpServerInstructions, - /** Additional directories to search for skills. */ + /** Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ @JsonProperty("skillDirectories") List skillDirectories, + /** Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("agentDirectories") List agentDirectories, + /** Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("instructionDirectories") List instructionDirectories, + /** Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("hookDirectories") List hookDirectories, /** Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ @JsonProperty("ignoredSkillsLocations") List ignoredSkillsLocations, /** Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. */ @@ -136,13 +142,13 @@ public record SessionOptionsUpdateParams( @JsonProperty("skipEmbeddingRetrieval") Boolean skipEmbeddingRetrieval, /** Organization-level custom instructions to inject into the system prompt. */ @JsonProperty("organizationCustomInstructions") String organizationCustomInstructions, - /** Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. */ + /** Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. */ @JsonProperty("enableFileHooks") Boolean enableFileHooks, /** Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). */ @JsonProperty("enableHostGitOperations") Boolean enableHostGitOperations, /** Whether to enable cross-session store writes and reads. */ @JsonProperty("enableSessionStore") Boolean enableSessionStore, - /** Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. */ + /** Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. */ @JsonProperty("enableSkills") Boolean enableSkills, /** Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. */ @JsonProperty("contextTier") OptionsUpdateContextTier contextTier, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsApi.java index aed2de53fb..eb4cc591e8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsApi.java @@ -44,7 +44,7 @@ public final class SessionPermissionsApi { } /** - * Patch of permission policy fields to apply (omit a field to leave it unchanged). + * Replaces selected permission policy fields (rules, paths, URLs, exclusions, allow-all flags) on the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -60,7 +60,7 @@ public CompletableFuture configure(SessionPer } /** - * Pending permission request ID and the decision to apply (approve/reject and scope). + * Provides a decision for a pending tool permission request. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -76,7 +76,7 @@ public CompletableFuture } /** - * No parameters; returns currently-pending permission requests for the session. + * Reconstructs the set of pending tool permission requests from the session's event history. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -87,7 +87,7 @@ public CompletableFuture pendingRequest } /** - * Allow-all toggle for tool permission requests, with an optional telemetry source. + * Enables or disables automatic approval of tool permission requests for the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -103,7 +103,7 @@ public CompletableFuture setApproveAll(Se } /** - * Permission mode to apply for the session. + * Sets the permission mode for the session. `manual` follows the normal approval flow, `assisted` attaches LLM safety recommendations, and `allow-all` automatically approves permission requests. The result returns the authoritative post-mutation mode so callers can update local state without racing the `session.permissions_changed` notification. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -119,7 +119,7 @@ public CompletableFuture setMode(SessionPermiss } /** - * No parameters. + * Returns the current permission mode for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -130,7 +130,7 @@ public CompletableFuture getMode() { } /** - * Scope and add/remove instructions for modifying session- or location-scoped permission rules. + * Adds or removes session-scoped or location-scoped permission rules. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -146,7 +146,7 @@ public CompletableFuture modifyRules(Sessio } /** - * Toggles whether permission prompts should be bridged into session events for this client. + * Sets whether the client wants permission prompts bridged into session events. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -162,7 +162,7 @@ public CompletableFuture setRequired(Sessio } /** - * Clears session-scoped tool approvals and optionally clears location-scoped approvals and exact session-approved paths. + * Clears session-scoped tool approvals and, for full resets, exact session-approved paths. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -178,7 +178,7 @@ public CompletableFuture resetSes } /** - * Notification payload describing the permission prompt that the client just rendered. + * Notifies the runtime that a permission prompt UI has been shown to the user. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsFolderTrustApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsFolderTrustApi.java index 55bac08941..741e4ed737 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsFolderTrustApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsFolderTrustApi.java @@ -31,7 +31,7 @@ public final class SessionPermissionsFolderTrustApi { } /** - * Folder path to check for trust. + * Reports whether a folder is trusted according to the user's folder trust state. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture isTrusted } /** - * Folder path to add to trusted folders. + * Adds a folder to the user's trusted folders list. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsLocationsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsLocationsApi.java index 46ce8ef4d3..37f16bf40c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsLocationsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsLocationsApi.java @@ -31,7 +31,7 @@ public final class SessionPermissionsLocationsApi { } /** - * Working directory to resolve into a location-permissions key. + * Resolves the permission location key and type for a working directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture resolve(Sessi } /** - * Working directory to load persisted location permissions for. + * Applies persisted location-scoped tool approvals and allowed directories for a working directory to this session's permission service. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -63,7 +63,7 @@ public CompletableFuture apply(SessionPe } /** - * Location-scoped tool approval to persist. + * Persists a tool approval for a permission location and applies its rules to this session's live permission service. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsPathsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsPathsApi.java index ecf9d81b52..62ae0a193b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsPathsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsPathsApi.java @@ -31,7 +31,7 @@ public final class SessionPermissionsPathsApi { } /** - * No parameters; returns the session's recursive directory grants and exact session-approved paths. + * Returns the session's recursive directory grants, exact session-approved paths, and primary working directory. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture list() { } /** - * Directory path to add to the session's allowed directories. + * Adds a directory to the session's allow-list and activates conventional skill and agent definitions under it. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +58,7 @@ public CompletableFuture add(SessionPermission } /** - * Directory path to set as the session's new primary working directory. + * Updates the session's primary working directory used by the permission policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -74,7 +74,7 @@ public CompletableFuture updatePrima } /** - * Path to evaluate against the session's allowed directories. + * Reports whether a path falls within any of the session's allowed directories. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -90,7 +90,7 @@ public CompletableFuture * Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsUrlsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsUrlsApi.java index 5ca15960d2..3261b07033 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsUrlsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPermissionsUrlsApi.java @@ -31,7 +31,7 @@ public final class SessionPermissionsUrlsApi { } /** - * Whether the URL-permission policy should run in unrestricted mode. + * Toggles the runtime's URL-permission policy between unrestricted and restricted modes. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPlanApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPlanApi.java index 7805183ddf..daf85af7db 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPlanApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPlanApi.java @@ -31,7 +31,7 @@ public final class SessionPlanApi { } /** - * Identifies the target session. + * Reads the session plan file from the workspace. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture read() { } /** - * Replacement contents to write to the session plan file. + * Writes new content to the session plan file. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +58,7 @@ public CompletableFuture update(SessionPlanUpdateParams params) { } /** - * Identifies the target session. + * Deletes the session plan file from the workspace. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -69,7 +69,7 @@ public CompletableFuture delete() { } /** - * Identifies the target session. + * Reads todo rows from the session SQL database for plan rendering. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -80,7 +80,7 @@ public CompletableFuture readSqlTodos() { } /** - * Identifies the target session. + * Reads todo rows AND dependency edges from the session SQL database for structured progress UI. Same defensive behavior as readSqlTodos — returns empty arrays when the database, tables, or columns aren't available. Clients should call this on session start and after every `session.todos_changed` event to refresh structured-UI rendering. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java index 6a49785b30..3235108161 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java @@ -35,7 +35,7 @@ public final class SessionPluginsApi { } /** - * Identifies the target session. + * Lists globally installed, live, built-in, and enterprise-managed desired plugins using the live session's authoritative account, working directory, and retained managed policy. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -46,7 +46,7 @@ public CompletableFuture list() { } /** - * Plugin source resolved relative to the session's authoritative working directory. + * Installs a plugin using the live session's authoritative account, working directory, and retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -62,7 +62,7 @@ public CompletableFuture install(SessionPluginsInst } /** - * Name (or spec) of the plugin to uninstall. + * Uninstalls a plugin when permitted by the live session's retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -78,7 +78,7 @@ public CompletableFuture uninstall(SessionPluginsUninstallParams params) { } /** - * Name (or spec) of the plugin to update. + * Updates an installed plugin using the live session's authoritative account, working directory, and retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -94,7 +94,7 @@ public CompletableFuture update(SessionPluginsUpdate } /** - * Plugin names (or specs) to enable in the session's authoritative working directory. + * Enables installed plugins when permitted by the live session's retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -110,7 +110,7 @@ public CompletableFuture enable(SessionPluginsEnableParams params) { } /** - * Plugin names (or specs) to disable in the session's authoritative working directory. + * Disables installed plugins when permitted by the live session's retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -126,7 +126,7 @@ public CompletableFuture disable(SessionPluginsDisableParams params) { } /** - * Optional flags controlling which side effects the reload performs. + * Reloads the session's plugin set, refreshing MCP servers, custom agents, hooks, and skills cache so SDK-driven changes via `server.plugins.*` take effect immediately. *

* Invokes the method with no params, applying the runtime defaults. * @@ -139,7 +139,7 @@ public CompletableFuture reload() { } /** - * Optional flags controlling which side effects the reload performs. + * Reloads the session's plugin set, refreshing MCP servers, custom agents, hooks, and skills cache so SDK-driven changes via `server.plugins.*` take effect immediately. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -154,4 +154,33 @@ public CompletableFuture reload(SessionPluginsReloadParams params) { return caller.invoke("session.plugins.reload", _p, Void.class); } + /** + * Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + *

+ * Invokes the method with no params, applying the runtime defaults. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture retryManaged() { + return retryManaged(null); + } + + /** + * Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture retryManaged(SessionPluginsRetryManagedParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = params == null ? MAPPER.createObjectNode() : MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.plugins.retryManaged", _p, SessionPluginsRetryManagedResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsMarketplacesApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsMarketplacesApi.java index 3ec14c5cf7..c9682c21f8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsMarketplacesApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsMarketplacesApi.java @@ -31,7 +31,7 @@ public final class SessionPluginsMarketplacesApi { } /** - * Identifies the target session. + * Lists registered and enterprise-managed desired marketplaces using the live session's retained policy. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture list() { } /** - * Marketplace source and optional working directory for relative-path resolution. + * Adds a marketplace when permitted by the live session's retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +58,7 @@ public CompletableFuture add(SessionPlugins } /** - * Name of the marketplace to remove and an optional force flag. + * Removes a marketplace when permitted by the live session's retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -74,7 +74,7 @@ public CompletableFuture remove(SessionP } /** - * Name of the marketplace whose plugin catalog to fetch. + * Browses a marketplace resolved through the live session's working directory and retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -90,7 +90,7 @@ public CompletableFuture browse(SessionP } /** - * Optional marketplace name; omit to refresh all. + * Refreshes marketplaces resolved through the live session's working directory and retained managed policy. *

* Invokes the method with no params, applying the runtime defaults. * @@ -103,7 +103,7 @@ public CompletableFuture refresh() { } /** - * Optional marketplace name; omit to refresh all. + * Refreshes marketplaces resolved through the live session's working directory and retained managed policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedParams.java new file mode 100644 index 0000000000..24b687ca75 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.plugins.retryManaged} RPC method. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPluginsRetryManagedParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. */ + @JsonProperty("plugins") List plugins +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedResult.java new file mode 100644 index 0000000000..f2fc9b73cb --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Per-plugin outcomes of retrying the plugins required by the session's managed settings. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPluginsRetryManagedResult( + /** One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. */ + @JsonProperty("plugins") List plugins +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProviderApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProviderApi.java index 26ebee8489..8d3b283405 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProviderApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProviderApi.java @@ -31,7 +31,7 @@ public final class SessionProviderApi { } /** - * Optional model identifier to scope the endpoint snapshot to. + * Returns the provider endpoint and credentials the session is currently configured to talk to, so the caller can make inference calls directly against the same backend the session uses. *

* Invokes the method with no params, applying the runtime defaults. * @@ -44,7 +44,7 @@ public CompletableFuture getEndpoint() { } /** - * Optional model identifier to scope the endpoint snapshot to. + * Returns the provider endpoint and credentials the session is currently configured to talk to, so the caller can make inference calls directly against the same backend the session uses. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -60,7 +60,7 @@ public CompletableFuture getEndpoint(SessionPr } /** - * BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both. + * Adds BYOK providers and/or models to the session's registry at runtime, extending the additive registry built from the session's `providers`/`models` options. Both fields are optional, so a call may add providers only, models only, or both. Within a single call providers are registered before models, so a model may reference a provider added in the same call; across calls a model may reference any provider already registered (from session creation or a prior add). A model whose referenced provider is not registered by the end of the call is rejected. Newly added models become selectable via `model.list` / `model.switchTo` and are inherited by sub-agents spawned afterwards. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -76,7 +76,7 @@ public CompletableFuture add(SessionProviderAddParams } /** - * Authoritative BYOK provider and model registry snapshot to apply atomically to the session. + * Atomically updates the session's BYOK provider and model registry by applying the supplied snapshot, replacing existing entries, updating models, or removing entries absent from the snapshot. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -92,7 +92,7 @@ public CompletableFuture sync(SessionProviderSyncPara } /** - * Host-managed model selection ids to withdraw from the session's BYOK registry. + * Withdraws named host-managed models from the session's BYOK registry, leaving every other entry untouched. The scoped counterpart to `provider.sync`: a snapshot can only describe entries the caller knows about, so using it to remove one model silently withdraws rows registered by another source, such as a plugin calling `provider.add` at runtime. Naming what to remove leaves unrelated entries alone. Selection ids that are not registered are ignored, so withdrawal is idempotent. A provider is removed only when one of the withdrawn models was the last entry referencing it; a provider that simply has no models, which is the normal state while its rows are supplied by catalog discovery, is left in place. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersApi.java index 6f6dc8b5e5..f7dde45999 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersApi.java @@ -35,7 +35,7 @@ public final class SessionProvidersApi { } /** - * Identifies the target session. + * Returns adapter definitions and supported operations in this session's effective provider catalog, without running discovery. Does not list provider instances or select inference models. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -46,7 +46,7 @@ public CompletableFuture getCatalog() { } /** - * Provider discovery parameters. + * Discovers reachable instances using an adapter from this session's effective provider catalog and provider-specific discovery input. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -62,7 +62,7 @@ public CompletableFuture discover(SessionProvide } /** - * Provider status request parameters. + * Gets current health and version information for a discovered model-provider instance. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersModelsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersModelsApi.java index b309fc7c12..3f5855d9a8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersModelsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionProvidersModelsApi.java @@ -31,7 +31,7 @@ public final class SessionProvidersModelsApi { } /** - * Provider model inventory request parameters. + * Lists models installed or otherwise available from a discovered model-provider instance. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture list(SessionProviders } /** - * A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`. + * Translates a discovered model into the provider and model configuration needed to use it, and reports whether each is already registered in this session. Prepares only: it registers nothing, writes nothing, and performs no provider requests. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueApi.java index 101d1726f2..e38110708f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueApi.java @@ -31,7 +31,7 @@ public final class SessionQueueApi { } /** - * Identifies the target session. + * Returns the local session's pending user-facing queued items and steering messages. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture pendingItems() { } /** - * Identifies the target session. + * Returns the internal native queue snapshot for in-process session orchestration. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -53,7 +53,7 @@ CompletableFuture snapshot() { } /** - * Parameters for moving a queued item by stable id. + * Moves an addressable queued item to a public visible position. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -69,7 +69,7 @@ public CompletableFuture moveItem(SessionQueueMoveIt } /** - * Parameters for inserting a queued message at a public visible position. + * Inserts a new queued message at a public visible position. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -85,7 +85,7 @@ public CompletableFuture insertAt(SessionQueueInsert } /** - * Parameters for removing a queued item by stable id. + * Removes an addressable queued item by its stable id. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -101,7 +101,7 @@ public CompletableFuture removeAt(SessionQueueRemove } /** - * Parameters for editing a single queued message. + * Updates the text of an addressable single-message queue item. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -117,7 +117,7 @@ public CompletableFuture updateText(SessionQueueUp } /** - * Conditional withdrawal of a single user message, from its queue or from the running turn it started. + * Atomically withdraws an unchanged user message of a local session: from the queued or steering lane while unconsumed, or from the running turn it started while the model has not answered it and nothing the user sent after it is pending. Withdrawing from the running turn interrupts that turn and removes its events from history. A client retaining the original draft may restore it only when removed is true. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -133,7 +133,7 @@ public CompletableFuture withdrawMessage(Sess } /** - * Append to one pending steering message without changing its identity or delivery position. + * Atomically appends text and attachments to an unchanged, unconsumed local steering message. Returns updated=false if delivery or withdrawal already claimed the message. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -149,7 +149,7 @@ public CompletableFuture appendSteering(Sessio } /** - * Parameters for duplicating a queued item. + * Duplicates an addressable queued item immediately after its source. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -165,7 +165,7 @@ public CompletableFuture duplicateAt(SessionQueue } /** - * Parameters for acquiring or releasing the queued-lane drain pause. Acquisition is exclusive and non-idempotent: `paused: true` against an already-paused session fails with `queue_already_paused`. The pause is never released automatically — it is not tied to the caller's lifetime, so a client that exits without sending `paused: false` leaves the lane frozen. Release is unowned: `paused: false` clears the pause for any caller, including one that never acquired it. + * Acquires or releases the queued-lane drain pause. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -181,7 +181,7 @@ public CompletableFuture setDrainPaused(SessionQueueSetDrainPausedParams p } /** - * Parameters for steering a queued message into a live turn. + * Moves an addressable queued message into the live turn's steering lane. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -197,7 +197,7 @@ public CompletableFuture sendNow(SessionQueueSendNowP } /** - * Identifies the target session. + * Reports whether the local session has native queued work pending. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -208,7 +208,7 @@ CompletableFuture hasPending() { } /** - * Inputs for starting a deferred-idle drain. + * Begins a native deferred-idle drain when background work has quiesced. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -224,7 +224,7 @@ CompletableFuture beginDeferredIdleDrain(Sess } /** - * Inputs for completing a deferred-idle drain. + * Finishes a native deferred-idle drain and reports whether to drain queue work or emit idle. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -240,7 +240,7 @@ CompletableFuture finishDeferredIdleDrain(Se } /** - * Inputs for marking session.idle deferred in native state. + * Marks session.idle as deferred by native background work state. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -256,7 +256,7 @@ CompletableFuture deferSessionIdle(SessionQueueDeferSessionIdleParams para } /** - * Identifies the target session. + * Removes the most recently queued user-facing item (LIFO). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -267,7 +267,7 @@ public CompletableFuture removeMostRecent() } /** - * Identifies the target session. + * Clears all pending queued items on the local session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -278,7 +278,7 @@ public CompletableFuture clear() { } /** - * Internal filter for consuming queued system notifications. + * Consumes queued native system notifications matching an internal filter. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -294,7 +294,7 @@ CompletableFuture consumeSystemNotifications(Sessio } /** - * Identifies the target session. + * Enqueues the internal resume-pending wake item when orphan handling needs a follow-up turn. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -305,7 +305,7 @@ CompletableFuture enqueueResumePending() { } /** - * Identifies the target session. + * Drains the native local-session work queue for in-process session orchestration. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java index 3b1d844881..850afce76e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java @@ -27,6 +27,7 @@ record SessionQueueConsumeSystemNotificationsParams( /** Target session identifier */ @JsonProperty("sessionId") String sessionId, /** Opaque runtime-owned filter object. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("filter") Object filter ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaApi.java new file mode 100644 index 0000000000..15ecde4f84 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaApi.java @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code quota} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class SessionQuotaApi { + + private final RpcCaller caller; + private final String sessionId; + + /** @param caller the RPC transport function */ + SessionQuotaApi(RpcCaller caller, String sessionId) { + this.caller = caller; + this.sessionId = sessionId; + } + + /** + * Gets the session's current quota and account projection without making a network request. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture get() { + return caller.invoke("session.quota.get", java.util.Map.of("sessionId", this.sessionId), SessionQuotaGetResult.class); + } + + /** + * Refreshes the session's provider model catalog bypassing its cache, folds quota snapshots into session state, and returns the updated projection. Failures leave the last known quota intact. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture refresh() { + return caller.invoke("session.quota.refresh", java.util.Map.of("sessionId", this.sessionId), SessionQuotaRefreshResult.class); + } + + /** + * Returns and clears the session's pending quota warnings. Reading or refreshing quota does not drain warnings. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture> takeWarnings() { + return caller.invoke("session.quota.takeWarnings", java.util.Map.of("sessionId", this.sessionId), RpcMapper.INSTANCE.getTypeFactory().constructCollectionType(List.class, QuotaWarningProjection.class)); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaDelegateWarning.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaDelegateWarning.java new file mode 100644 index 0000000000..ed6331a96f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaDelegateWarning.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Existing delegation guidance for an account without delegation access. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionQuotaDelegateWarning( + /** User-facing guidance. */ + @JsonProperty("text") String text, + /** Link to upgrade the account. */ + @JsonProperty("url") String url +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaGetParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaGetParams.java new file mode 100644 index 0000000000..1c66851a3d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaGetParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the target session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionQuotaGetParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaGetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaGetResult.java new file mode 100644 index 0000000000..cc92c0199f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaGetResult.java @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The incumbent session-owned quota and account projection. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionQuotaGetResult( + /** Known quota snapshots, keyed by the provider's quota type. */ + @JsonProperty("snapshots") Map snapshots, + /** Provider-owned account quota state, including snapshots without numeric balances. */ + @JsonProperty("providerQuotas") List providerQuotas, + /** Whether the account uses the free limited Copilot plan. */ + @JsonProperty("isFreeUser") Boolean isFreeUser, + /** Whether the account uses token-based billing. */ + @JsonProperty("isTbbUser") Boolean isTbbUser, + /** Resolved Copilot plan tier. */ + @JsonProperty("planTier") SessionQuotaPlanTier planTier, + /** Whether premium-request costs are billable. */ + @JsonProperty("premiumRequestsBillable") Boolean premiumRequestsBillable, + /** Whether model cost columns should be shown. */ + @JsonProperty("modelCostColumnVisible") Boolean modelCostColumnVisible, + /** Whether the account can delegate tasks to GitHub. */ + @JsonProperty("delegateAvailable") Boolean delegateAvailable, + /** Whether the account can sign up for Copilot Free. */ + @JsonProperty("canSignupForCopilotFree") Boolean canSignupForCopilotFree, + /** Whether dynamic workflows are enabled for the active account. */ + @JsonProperty("dynamicWorkflowsEnabled") Boolean dynamicWorkflowsEnabled, + /** Whether dynamic workflows are visible under the session's feature flags. */ + @JsonProperty("dynamicWorkflowsUiVisible") Boolean dynamicWorkflowsUiVisible, + /** Upgrade link for a free account. */ + @JsonProperty("upgradeUrl") String upgradeUrl, + /** Existing delegation warning for a free account. */ + @JsonProperty("delegateWarning") SessionQuotaDelegateWarning delegateWarning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaPlanTier.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaPlanTier.java new file mode 100644 index 0000000000..fc2e5c53c9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaPlanTier.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Copilot plan tier used by the session quota projection. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum SessionQuotaPlanTier { + /** The {@code free} variant. */ + FREE("free"), + /** The {@code edu} variant. */ + EDU("edu"), + /** The {@code pro} variant. */ + PRO("pro"), + /** The {@code pro_plus} variant. */ + PRO_PLUS("pro_plus"), + /** The {@code business} variant. */ + BUSINESS("business"), + /** The {@code enterprise} variant. */ + ENTERPRISE("enterprise"), + /** The {@code max} variant. */ + MAX("max"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + SessionQuotaPlanTier(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SessionQuotaPlanTier fromValue(String value) { + for (SessionQuotaPlanTier v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SessionQuotaPlanTier value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaRefreshParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaRefreshParams.java new file mode 100644 index 0000000000..ac51e99123 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaRefreshParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the target session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionQuotaRefreshParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaRefreshResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaRefreshResult.java new file mode 100644 index 0000000000..0f0892d284 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaRefreshResult.java @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The incumbent session-owned quota and account projection. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionQuotaRefreshResult( + /** Known quota snapshots, keyed by the provider's quota type. */ + @JsonProperty("snapshots") Map snapshots, + /** Provider-owned account quota state, including snapshots without numeric balances. */ + @JsonProperty("providerQuotas") List providerQuotas, + /** Whether the account uses the free limited Copilot plan. */ + @JsonProperty("isFreeUser") Boolean isFreeUser, + /** Whether the account uses token-based billing. */ + @JsonProperty("isTbbUser") Boolean isTbbUser, + /** Resolved Copilot plan tier. */ + @JsonProperty("planTier") SessionQuotaPlanTier planTier, + /** Whether premium-request costs are billable. */ + @JsonProperty("premiumRequestsBillable") Boolean premiumRequestsBillable, + /** Whether model cost columns should be shown. */ + @JsonProperty("modelCostColumnVisible") Boolean modelCostColumnVisible, + /** Whether the account can delegate tasks to GitHub. */ + @JsonProperty("delegateAvailable") Boolean delegateAvailable, + /** Whether the account can sign up for Copilot Free. */ + @JsonProperty("canSignupForCopilotFree") Boolean canSignupForCopilotFree, + /** Whether dynamic workflows are enabled for the active account. */ + @JsonProperty("dynamicWorkflowsEnabled") Boolean dynamicWorkflowsEnabled, + /** Whether dynamic workflows are visible under the session's feature flags. */ + @JsonProperty("dynamicWorkflowsUiVisible") Boolean dynamicWorkflowsUiVisible, + /** Upgrade link for a free account. */ + @JsonProperty("upgradeUrl") String upgradeUrl, + /** Existing delegation warning for a free account. */ + @JsonProperty("delegateWarning") SessionQuotaDelegateWarning delegateWarning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaSnapshot.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaSnapshot.java new file mode 100644 index 0000000000..996bdf7227 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaSnapshot.java @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Session quota snapshot, preserving the incumbent numeric units and reset metadata. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionQuotaSnapshot( + /** Whether the entitlement is unlimited. */ + @JsonProperty("isUnlimitedEntitlement") Boolean isUnlimitedEntitlement, + /** Entitled quantity in this quota's units. */ + @JsonProperty("entitlementRequests") Double entitlementRequests, + /** Consumed quantity in this quota's units. */ + @JsonProperty("usedRequests") Double usedRequests, + /** Whether usage is allowed after quota exhaustion. */ + @JsonProperty("usageAllowedWithExhaustedQuota") Boolean usageAllowedWithExhaustedQuota, + /** Additional usage in this quota's units. */ + @JsonProperty("overage") Double overage, + /** Whether additional usage is allowed after quota exhaustion. */ + @JsonProperty("overageAllowedWithExhaustedQuota") Boolean overageAllowedWithExhaustedQuota, + /** Percentage of the entitlement remaining. */ + @JsonProperty("remainingPercentage") Double remainingPercentage, + /** Quota reset time in milliseconds since the Unix epoch, when known. */ + @JsonProperty("resetDateEpochMs") Double resetDateEpochMs, + /** Whether the reset time is estimated. */ + @JsonProperty("resetDateEstimated") Boolean resetDateEstimated, + /** Whether the provider reports available quota. */ + @JsonProperty("hasQuota") Boolean hasQuota, + /** Whether this quota uses token-based billing. */ + @JsonProperty("tokenBasedBilling") Boolean tokenBasedBilling, + /** Additional-usage budget cap, when provided. */ + @JsonProperty("overageEntitlement") Double overageEntitlement +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaTakeWarningsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaTakeWarningsParams.java new file mode 100644 index 0000000000..2a96fdd5a2 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQuotaTakeWarningsParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the target session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionQuotaTakeWarningsParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRemoteApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRemoteApi.java index bb1cfa0e25..015c69f830 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRemoteApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRemoteApi.java @@ -31,7 +31,7 @@ public final class SessionRemoteApi { } /** - * Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. + * Enables remote session export or steering. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture enable(SessionRemoteEnablePa } /** - * Identifies the target session. + * Disables remote session export and steering. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -58,7 +58,7 @@ public CompletableFuture disable() { } /** - * New remote-steerability state to persist as a `session.remote_steerable_changed` event. + * Persists a remote-steerability change emitted by the host as a session event. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java index 9c235ef2e3..9a56863901 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java @@ -113,6 +113,8 @@ public final class SessionRpc { public final SessionEventLogApi eventLog; /** API methods for the {@code usage} namespace. */ public final SessionUsageApi usage; + /** API methods for the {@code quota} namespace. */ + public final SessionQuotaApi quota; /** API methods for the {@code limitPrediction} namespace. */ public final SessionLimitPredictionApi limitPrediction; /** API methods for the {@code remote} namespace. */ @@ -173,6 +175,7 @@ public SessionRpc(RpcCaller caller, String sessionId) { this.queue = new SessionQueueApi(caller, sessionId); this.eventLog = new SessionEventLogApi(caller, sessionId); this.usage = new SessionUsageApi(caller, sessionId); + this.quota = new SessionQuotaApi(caller, sessionId); this.limitPrediction = new SessionLimitPredictionApi(caller, sessionId); this.remote = new SessionRemoteApi(caller, sessionId); this.visibility = new SessionVisibilityApi(caller, sessionId); @@ -180,7 +183,7 @@ public SessionRpc(RpcCaller caller, String sessionId) { } /** - * Identifies the target session. + * Suspends the session while preserving persisted state for later resume. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -191,7 +194,7 @@ public CompletableFuture suspend() { } /** - * Parameters for sending a user message to the session + * Sends a user message to the session and returns its message ID. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -207,7 +210,7 @@ public CompletableFuture send(SessionSendParams params) { } /** - * Parameters for sending zero or more user messages to the session in a single turn. Remote-backed (Mission Control) sessions do not support this method and will return an error. + * Sends zero or more user messages to the session in a single turn and returns their message IDs. All provided messages are appended to the conversation in order, then exactly one agent turn runs over the resulting history. When the list is empty, one turn runs over the existing history with no new user message. Remote-backed (Mission Control) sessions do not support this method and will return an error. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -223,7 +226,7 @@ public CompletableFuture sendMessages(SessionSendMess } /** - * Internal request for sending a system notification. + * Queues or sends an internal system notification to the session according to its passive policy. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -239,7 +242,7 @@ CompletableFuture sendSystemNotification(SessionSendSystemNotificationPara } /** - * Parameters for aborting the current turn + * Aborts the current agent turn. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -255,7 +258,7 @@ public CompletableFuture abort(SessionAbortParams params) { } /** - * Parameters for interrupting the main agent turn. + * Interrupts the current main agent turn while leaving running background work (subagents, sidekicks, and promoted attached shells) alive. No-op when the main loop is not processing. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -271,18 +274,18 @@ public CompletableFuture interruptMainTurn(Sessi } /** - * Identifies the target session. + * Cancels every running background agent (task-registry subagents plus sidekick agents) without interrupting the main agent loop. Promoted attached shells are left running. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 */ @CopilotExperimental - public CompletableFuture cancelAllBackgroundAgents() { - return caller.invoke("session.cancelAllBackgroundAgents", java.util.Map.of("sessionId", this.sessionId), Void.class); + public CompletableFuture cancelAllBackgroundAgents() { + return caller.invoke("session.cancelAllBackgroundAgents", java.util.Map.of("sessionId", this.sessionId), Long.class); } /** - * Parameters for shutting down the session + * Shuts down the session and persists its final state. Awaits any deferred sessionEnd hooks before resolving so user-supplied hook scripts complete before the runtime tears down. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -298,7 +301,7 @@ public CompletableFuture shutdown(SessionShutdownParams params) { } /** - * Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. + * Emits a user-visible session log event. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java index a13ef559ef..b780e59b38 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java @@ -31,7 +31,7 @@ public final class SessionSandboxApi { } /** - * Identifies the target session. + * Returns whether managed policy requires sandbox enforcement and whether an enforcement failure has permanently blocked the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,18 @@ public CompletableFuture getEnforcemen } /** - * Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. + * Lists possible secret-bearing environment variables available to new sandboxed shells that are not already covered by credential masking. Uses local name rules and known-provider host suggestions, never returns secret values, and changes no settings or network permissions. Returns no suggestions while the session is not sandboxed. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getCredentialSuggestions() { + return caller.invoke("session.sandbox.getCredentialSuggestions", java.util.Map.of("sessionId", this.sessionId), SessionSandboxGetCredentialSuggestionsResult.class); + } + + /** + * Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +69,7 @@ public CompletableFuture disableForSessio } /** - * Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. + * Adds the path offered by a pending sandbox escalation permission request's sandboxPathGrant to the session's sandbox policy and approves the request, so the blocked operation re-runs inside the sandbox rather than outside it. The request is rejected unless the exact request is still pending, carries a sandboxPathGrant, and the grant still takes effect under the current managed policy. Does not persist the path; hosts that store sandbox settings save it themselves. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsParams.java new file mode 100644 index 0000000000..c587908619 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the target session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSandboxGetCredentialSuggestionsParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsResult.java new file mode 100644 index 0000000000..2f883728f1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSandboxGetCredentialSuggestionsResult( + /** Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. */ + @JsonProperty("suggestions") List suggestions +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionScheduleApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionScheduleApi.java index a6e8ad88d7..0b6a90aca9 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionScheduleApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionScheduleApi.java @@ -31,7 +31,7 @@ public final class SessionScheduleApi { } /** - * Identifies the target session. + * Lists the session's currently active scheduled prompts. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture list() { } /** - * Identifies the target session. + * Hydrates the native schedule registry from persisted session events. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -53,7 +53,7 @@ CompletableFuture hydrate() { } /** - * Identifies the target session. + * Reports whether the session has an active self-paced scheduled prompt. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -64,7 +64,7 @@ CompletableFuture hasSelfPaced() { } /** - * Register a relative-interval scheduled prompt. + * Registers a relative-interval scheduled prompt. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -80,7 +80,7 @@ CompletableFuture add(SessionScheduleAddParams params) { } /** - * Register a cron scheduled prompt. + * Registers a recurring cron scheduled prompt. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -96,7 +96,7 @@ CompletableFuture addCron(SessionScheduleAddCronParams params } /** - * Register an absolute-time scheduled prompt. + * Registers an absolute-time scheduled prompt. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -112,7 +112,7 @@ CompletableFuture addAt(SessionScheduleAddAtParams params) { } /** - * Register a self-paced scheduled prompt. + * Registers a self-paced scheduled prompt. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -128,7 +128,7 @@ CompletableFuture addSelfPaced(SessionScheduleAddSelfPacedPar } /** - * Re-arm a self-paced scheduled prompt. + * Re-arms an active self-paced scheduled prompt. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -144,7 +144,7 @@ CompletableFuture rearmSelfPaced(SessionScheduleRearmSelfPace } /** - * Identifier of the scheduled prompt to remove. + * Removes a scheduled prompt by id. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSettingsApi.java index 213b7de0a4..f07d028f93 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSettingsApi.java @@ -31,7 +31,7 @@ final class SessionSettingsApi { } /** - * Identifies the target session. + * Returns a redacted snapshot of session runtime settings, with secrets and raw feature flags excluded. Internal: the runtime settings shape is a runtime-internal surface and is deliberately kept out of the public SDK, because consumers should not depend on the runtime's internal settings layout. It remains callable in-process and is expected to be reworked as the runtime internals are consolidated. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ CompletableFuture snapshot() { } /** - * Named Rust-owned settings predicate to evaluate for this session. + * Evaluates a named Rust-owned settings predicate without exposing raw feature flags. Internal: the raw feature-flag names and composition are runtime-internal, so this predicate-evaluation helper is kept out of the public SDK surface and is callable in-process only. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionShellApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionShellApi.java index ebfd1a9c7d..6d3187ef75 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionShellApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionShellApi.java @@ -31,7 +31,7 @@ public final class SessionShellApi { } /** - * Shell command to run, with optional working directory and timeout in milliseconds. Spawn failures return an RPC error. + * Starts a shell command, returning an RPC error if it cannot be spawned. The command runs as the leader of its own process group (POSIX) or in a dedicated job object (Windows), so a forced termination — via "shell.kill", the request timeout, or session disposal — signals that whole group/job rather than only the direct child. Two gaps are worth planning for: a command that exits on its own does not trigger that teardown, and on POSIX a descendant that moves itself into a new session or process group (for example via "setsid") leaves the signalled group, so either can leave a background process running. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture exec(SessionShellExecParams par } /** - * Identifier of a process previously returned by "shell.exec" and the signal to send. + * Sends a signal to a shell process previously started via "shell.exec". The signal targets the command's whole process group (POSIX) or job object (Windows), so descendants still in that group are signalled too, not just the direct child. On POSIX a descendant that moved itself into a new session or process group (for example via "setsid") is no longer in the signalled group and survives. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -63,7 +63,7 @@ public CompletableFuture kill(SessionShellKillParams par } /** - * User-requested shell command and cancellation handle. + * Executes a user-requested shell command through the session runtime. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -79,7 +79,7 @@ public CompletableFuture executeUserRequ } /** - * User-requested shell execution cancellation handle. + * Cancels a user-requested shell command by request ID. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSkillsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSkillsApi.java index f6cceb98b9..e21c294b31 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSkillsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSkillsApi.java @@ -31,7 +31,7 @@ public final class SessionSkillsApi { } /** - * Identifies the target session. + * Lists skills available to the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture list() { } /** - * Identifies the target session. + * Returns the skills that have been invoked during this session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -53,7 +53,7 @@ public CompletableFuture getInvoked() { } /** - * Name of the skill to enable for the session. + * Enables a skill for the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -69,7 +69,7 @@ public CompletableFuture enable(SessionSkillsEnableParams params) { } /** - * Name of the skill to disable for the session. + * Disables a skill for the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -85,7 +85,7 @@ public CompletableFuture disable(SessionSkillsDisableParams params) { } /** - * Identifies the target session. + * Reloads skill definitions for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -96,7 +96,7 @@ public CompletableFuture reload() { } /** - * Identifies the target session. + * Ensures the session's skill definitions have been loaded from disk. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTasksApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTasksApi.java index c6ca1335de..9e78691586 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTasksApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTasksApi.java @@ -31,7 +31,7 @@ public final class SessionTasksApi { } /** - * Agent type, prompt, name, and optional description and model override for the new task. + * Starts a background agent task in the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture startAgent(SessionTasksSt } /** - * Identifies the target session. + * Lists background tasks tracked by the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -58,7 +58,7 @@ public CompletableFuture list() { } /** - * Registers or reclaims a client-owned task. + * Registers a client-owned task, or reclaims an orphaned task belonging to the same extension principal. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -74,7 +74,7 @@ public CompletableFuture register(SessionTasksRegist } /** - * Updates a client-owned task. + * Publishes generic progress or a terminal outcome for a client-owned task. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -90,7 +90,7 @@ public CompletableFuture update(SessionTasksUpdatePara } /** - * Identifies the target session. + * Refreshes metadata for any detached background shells the runtime knows about. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -101,7 +101,7 @@ public CompletableFuture refresh() { } /** - * Identifies the target session. + * Waits for all in-flight background tasks and any follow-up turns to settle. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -112,7 +112,7 @@ public CompletableFuture waitForPending() { } /** - * Identifier of the background task to fetch progress for. + * Returns progress information for a background task by ID. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -128,7 +128,7 @@ public CompletableFuture getProgress(SessionTasks } /** - * Identifies the target session. + * Returns the first sync-waiting task that can currently be promoted to background mode. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -139,7 +139,7 @@ public CompletableFuture getCurrentPromo } /** - * Identifier of the task to promote to background mode. + * Promotes an eligible synchronously-waited task so it continues running in the background. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -155,7 +155,7 @@ public CompletableFuture promoteToBackgro } /** - * Identifies the target session. + * Atomically promotes the first promotable sync-waiting task to background mode and returns it. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -166,7 +166,7 @@ public CompletableFuture promoteCu } /** - * Identifier of the background task to cancel. + * Cancels a background task. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -182,7 +182,7 @@ public CompletableFuture cancel(SessionTasksCancelPara } /** - * Identifier of the completed or cancelled task to remove from tracking. + * Removes a completed or cancelled background task from tracking. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -198,7 +198,7 @@ public CompletableFuture remove(SessionTasksRemovePara } /** - * Identifier of the target agent task, message content, and optional sender agent ID. + * Sends a message to a background agent task. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTelemetryApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTelemetryApi.java index 42589661ef..d74f8366da 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTelemetryApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionTelemetryApi.java @@ -31,7 +31,7 @@ public final class SessionTelemetryApi { } /** - * Identifies the target session. + * Gets the telemetry engagement ID currently associated with the session, when available. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture getEngagementId( } /** - * Feature override key/value pairs to attach to subsequent telemetry events from this session. + * Sets feature override key/value pairs to attach to subsequent telemetry events for the session. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsApi.java index 62593a3588..250478499b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsApi.java @@ -31,7 +31,7 @@ public final class SessionToolsApi { } /** - * A tool name and arguments to execute through the session's native invocation pipeline. + * Executes one tool from the session's currently offered tool set through the native invocation pipeline. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture execute(SessionToolsExecuteParams params) { } /** - * Options controlling how Rust-owned built-in tool descriptors are materialized. + * Returns the Rust-owned built-in tool descriptors used to construct the session's offered tool set. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -63,7 +63,7 @@ public CompletableFuture getBuiltinDesc } /** - * Task-completion tool arguments and final result used to build a label-safe session event payload. + * Projects a completed task_complete tool call into its label-safe session event payload. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -79,7 +79,7 @@ public CompletableFuture taskCompleteEv } /** - * Pending external tool call request ID, with the tool result or an error describing why it failed. + * Provides the result for a pending external tool call. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -95,7 +95,18 @@ public CompletableFuture handlePendingT } /** - * Identifies the target session. + * Lists the external tool calls of the session and its sub-agents that are still waiting for session.tools.handlePendingToolCall. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture listPendingRequests() { + return caller.invoke("session.tools.listPendingRequests", java.util.Map.of("sessionId", this.sessionId), SessionToolsListPendingRequestsResult.class); + } + + /** + * Resolves, builds, and validates the runtime tool list for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -106,7 +117,7 @@ public CompletableFuture initializeAndValidate() { } /** - * Identifies the target session. + * Returns lightweight metadata for the session's currently initialized tools. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -117,7 +128,7 @@ public CompletableFuture getCurrentMetadat } /** - * Complete externally implemented tool list for the calling connection. An empty list removes every tool previously supplied by that connection. + * Atomically replaces the complete externally implemented tool list supplied by the calling connection. Built-in, MCP/plugin, extension-discovered, subagent, and tools supplied by other connections remain unchanged. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -133,7 +144,7 @@ public CompletableFuture set(SessionToolsSetParams params) { } /** - * Subagent settings to apply to the current session + * Sets the current session's live subagent settings override, which takes precedence over persisted user settings until cleared. Persisted user settings remain the source of truth for future sessions. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java index e60023c3aa..0e118ff815 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java @@ -29,6 +29,7 @@ public record SessionToolsExecuteParams( /** Name of the currently offered tool to execute. */ @JsonProperty("name") String name, /** Arguments supplied to the tool. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("arguments") Object arguments, /** Optional identifier used to correlate this invocation with its tool call. */ @JsonProperty("toolCallId") String toolCallId diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsListPendingRequestsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsListPendingRequestsParams.java new file mode 100644 index 0000000000..8a10167180 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsListPendingRequestsParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * No parameters; returns the external tool calls of the session and its sub-agents that are still waiting for a result. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionToolsListPendingRequestsParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsListPendingRequestsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsListPendingRequestsResult.java new file mode 100644 index 0000000000..c7b17b4928 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsListPendingRequestsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * External tool calls still waiting for a result. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionToolsListPendingRequestsResult( + /** External tool calls of the session and its sub-agents that session.tools.handlePendingToolCall would still accept, in the order they were requested. Includes calls that were pending when the session was last suspended and resumed with pending work continued, so a host that did not observe the original external_tool.requested event can answer them. */ + @JsonProperty("items") List items +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java index 9902fb8a99..56fbf48a11 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java @@ -27,6 +27,7 @@ public record SessionToolsTaskCompleteEventDataParams( /** Target session identifier */ @JsonProperty("sessionId") String sessionId, /** Arguments supplied to the completed task_complete tool call. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("toolArgs") Object toolArgs, /** Final expanded result returned by the task_complete tool. */ @JsonProperty("finalResult") ToolResultExpanded finalResult diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUiApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUiApi.java index 7feccbd56a..5187b51774 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUiApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUiApi.java @@ -31,7 +31,7 @@ public final class SessionUiApi { } /** - * Transient question to answer without adding it to conversation history. + * Runs a transient no-tools model query against the current conversation context. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture ephemeralQuery(SessionUi } /** - * Prompt message and JSON schema describing the form fields to elicit from the user. + * Requests structured input from a UI-capable client. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -63,7 +63,7 @@ public CompletableFuture elicitation(SessionUiElicit } /** - * Pending elicitation request ID and the user's response (accept/decline/cancel + form values). + * Provides the user response for a pending elicitation request. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -79,7 +79,7 @@ public CompletableFuture handlePendingE } /** - * Pending elicitation request ID and the user's response (accept/decline/cancel + form values). + * Resolves a pending elicitation request after direct interaction in the trusted in-process client. Only an accepted response to the built-in ask_user tool can become trusted human evidence. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -95,7 +95,7 @@ CompletableFuture handleHumanAskUser(SessionUiHandleHumanAs } /** - * Request ID of a pending `user_input.requested` event and the user's response. + * Resolves a pending `user_input.requested` event with the user's response. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -111,7 +111,7 @@ public CompletableFuture handlePendingUse } /** - * Request ID of a pending `user_input.requested` event and the user's response. + * Resolves a pending `user_input.requested` event after direct interaction in the trusted in-process client. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -127,7 +127,7 @@ CompletableFuture handleHumanUserInput(SessionUiHandleHum } /** - * Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). + * Resolves a pending `sampling.requested` event with a sampling result, or rejects it. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -143,7 +143,7 @@ public CompletableFuture handlePendingSamp } /** - * Request ID of a pending `auto_mode_switch.requested` event and the user's response. + * Resolves a pending `auto_mode_switch.requested` event with the user's accept/decline decision. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -159,7 +159,7 @@ public CompletableFuture handlePendi } /** - * Request ID of a pending `session_limits_exhausted.requested` event and the user's selected limit action. + * Resolves a pending `session_limits_exhausted.requested` event with the user's selected limit action. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -175,7 +175,7 @@ public CompletableFuture han } /** - * Request ID of a pending `exit_plan_mode.requested` event and the user's response. + * Resolves a pending `exit_plan_mode.requested` event with the user's response. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -191,7 +191,7 @@ public CompletableFuture handlePending } /** - * Request ID of a pending `exit_plan_mode.requested` event and the user's response. + * Resolves a pending `exit_plan_mode.requested` event after direct interaction in the trusted in-process client. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -207,7 +207,7 @@ CompletableFuture handleHumanExitPlanMode(SessionUiHandle } /** - * Identifies the target session. + * Registers an in-process handler for auto-mode-switch requests so the server bridge skips dispatch. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -218,7 +218,7 @@ public CompletableFuture reg } /** - * Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. + * Unregisters a previously-registered in-process auto-mode-switch handler by its opaque handle. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageApi.java index 16ded9d6b6..75a19eadb1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageApi.java @@ -19,6 +19,8 @@ @javax.annotation.processing.Generated("copilot-sdk-codegen") public final class SessionUsageApi { + private static final com.fasterxml.jackson.databind.ObjectMapper MAPPER = RpcMapper.INSTANCE; + private final RpcCaller caller; private final String sessionId; @@ -29,7 +31,7 @@ public final class SessionUsageApi { } /** - * Identifies the target session. + * Gets accumulated usage metrics for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -39,4 +41,20 @@ public CompletableFuture getMetrics() { return caller.invoke("session.usage.getMetrics", java.util.Map.of("sessionId", this.sessionId), SessionUsageGetMetricsResult.class); } + /** + * Internal host-only replacement of absolute code-change totals reported by a relay host. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture setCodeChanges(SessionUsageSetCodeChangesParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.usage.setCodeChanges", _p, Void.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageGetMetricsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageGetMetricsResult.java index a38afd7042..1a771a239a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageGetMetricsResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageGetMetricsResult.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; import java.time.OffsetDateTime; +import java.util.List; import java.util.Map; import javax.annotation.processing.Generated; @@ -26,6 +27,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record SessionUsageGetMetricsResult( + /** Completeness of totalNanoAiu. Numeric totals remain the reported subtotal; zero is not a claim of free usage when unavailable. */ + @JsonProperty("aiCreditsStatus") AiCreditsStatus aiCreditsStatus, /** Total user-initiated premium request cost across all models (may be fractional due to multipliers) */ @JsonProperty("totalPremiumRequestCost") Double totalPremiumRequestCost, /** Raw count of user-initiated API requests */ @@ -42,6 +45,9 @@ public record SessionUsageGetMetricsResult( @JsonProperty("codeChanges") UsageMetricsCodeChanges codeChanges, /** Per-model token and request metrics, keyed by model identifier */ @JsonProperty("modelMetrics") Map modelMetrics, + /** Provider-attributed model metrics, ordered by first observed provider and model. +Null attribution preserves historical usage whose provider or model was not recorded. */ + @JsonProperty("providerModelMetrics") List providerModelMetrics, /** Per-agent usage metrics, keyed by agent instance identifier. The main conversation uses the stable key `main`. */ @JsonProperty("agentMetrics") Map agentMetrics, /** Currently active model identifier */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageSetCodeChangesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageSetCodeChangesParams.java new file mode 100644 index 0000000000..d8a963a75a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionUsageSetCodeChangesParams.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Internal absolute code-change totals reported by the owning host. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionUsageSetCodeChangesParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** Absolute added-line total, replacing the previous reading. */ + @JsonProperty("linesAdded") Double linesAdded, + /** Absolute removed-line total, replacing the previous reading. */ + @JsonProperty("linesRemoved") Double linesRemoved, + /** Absolute changed-file count; omission preserves the previous count. */ + @JsonProperty("filesCount") Double filesCount +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionVisibilityApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionVisibilityApi.java index 54f38c2614..b942828e10 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionVisibilityApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionVisibilityApi.java @@ -31,7 +31,7 @@ public final class SessionVisibilityApi { } /** - * Identifies the target session. + * Returns the session's current Mission Control sharing status and shareable GitHub URL. Reflects whether the synced session is visible to repository readers ("repo") or restricted to its creator and collaborators ("unshared"). * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +42,7 @@ public CompletableFuture get() { } /** - * Desired sharing status for the session. + * Sets the session's Mission Control sharing status, controlling whether the synced session is visible to repository readers. Returns the effective status and shareable GitHub URL after the change. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowApi.java index 2b9e81e42f..e746033b39 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowApi.java @@ -35,7 +35,7 @@ public final class SessionWorkflowApi { } /** - * Parameters for invoking a registered workflow. + * Runs a registered dynamic workflow by name at the top level. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -51,7 +51,7 @@ public CompletableFuture run(SessionWorkflowRunParams } /** - * Parameters for resuming a workflow run from its persisted identity. + * Resumes a dynamic workflow run using its persisted name, arguments, journal, and accounting. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -67,7 +67,7 @@ public CompletableFuture resume(SessionWorkflowResu } /** - * Internal parameters for invoking a registered workflow from a tool. + * Internal tool-originated dynamic workflow invocation. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -83,7 +83,7 @@ CompletableFuture runFromTool(SessionWorkflowRunFromToolParam } /** - * Internal parameters for resuming a workflow run from a tool. + * Internal tool-originated dynamic workflow resume. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -99,7 +99,7 @@ CompletableFuture resumeFromTool(SessionWorkflowResumeFrom } /** - * Parameters for retrieving a workflow run. + * Gets the current or settled envelope for a dynamic workflow run. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -115,7 +115,7 @@ public CompletableFuture getRun(SessionWorkflowGetR } /** - * Parameters for paging workflow runs. + * Lists durable dynamic workflow runs for this session in creation order. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -131,7 +131,7 @@ public CompletableFuture listRuns(SessionWorkflow } /** - * Parameters for retrieving a workflow run. + * Gets durable and live observability detail for one dynamic workflow run. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -147,7 +147,7 @@ public CompletableFuture getRunDetail(Session } /** - * Parameters for paging workflow progress. + * Pages durable progress for one dynamic workflow run. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -163,7 +163,7 @@ public CompletableFuture getRunProgress(Ses } /** - * Parameters for cancelling a workflow run. + * Requests cancellation of a dynamic workflow run and returns its run envelope. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -179,7 +179,7 @@ public CompletableFuture cancel(SessionWorkflowCanc } /** - * Parameters for pausing a running workflow. + * Pauses a running dynamic workflow and returns its settled run envelope. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -195,7 +195,7 @@ public CompletableFuture pause(SessionWorkflowPauseP } /** - * Parameters for an owned durable pause checkpoint. + * Atomically pauses an owned dynamic workflow attempt at a durable checkpoint. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -211,7 +211,7 @@ CompletableFuture pauseAtCheckpoint(SessionWorkfl } /** - * Parameters for recording workflow progress. + * Records a batch of ordered dynamic workflow progress lines. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -227,7 +227,7 @@ public CompletableFuture log(SessionWorkflowLogParams params) { } /** - * Parameters for one workflow-scoped subagent call. + * Runs one dynamic-workflow-scoped subagent and returns its result. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalApi.java index 0909931439..70bc1b47e2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalApi.java @@ -31,7 +31,7 @@ public final class SessionWorkflowJournalApi { } /** - * Parameters for reading a workflow journal entry. + * Reads a memoized dynamic workflow journal entry. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -47,7 +47,7 @@ public CompletableFuture get(SessionWorkflowJou } /** - * Parameters for storing a workflow journal entry. + * Stores a memoized dynamic workflow journal entry. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java index 890c69647e..6cd69c5476 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java @@ -33,6 +33,7 @@ public record SessionWorkflowJournalPutParams( /** Namespaced journal key. */ @JsonProperty("key") String key, /** JSON result to memoize. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("resultJson") Object resultJson ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java index d68976fb76..78b199562e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java @@ -29,6 +29,7 @@ record SessionWorkflowRunFromToolParams( /** Registered workflow name. */ @JsonProperty("name") String name, /** Workflow input value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("args") Object args, /** Tool-originated workflow invocation options. */ @JsonProperty("options") WorkflowToolRunOptions options, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java index 642e2f7fcf..84883913ff 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java @@ -29,6 +29,7 @@ public record SessionWorkflowRunParams( /** Registered workflow name. */ @JsonProperty("name") String name, /** Workflow input value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("args") Object args, /** Workflow invocation options. */ @JsonProperty("options") WorkflowRunOptions options diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkingDirectoryContextWithClient.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkingDirectoryContextWithClient.java new file mode 100644 index 0000000000..d909895e2d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkingDirectoryContextWithClient.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * A working-directory context together with the client that produced it. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionWorkingDirectoryContextWithClient( + /** Current working directory path */ + @JsonProperty("cwd") String cwd, + /** Root directory of the git repository */ + @JsonProperty("gitRoot") String gitRoot, + /** Repository identifier derived from the git remote URL */ + @JsonProperty("repository") String repository, + /** Hosting platform type of the repository */ + @JsonProperty("hostType") String hostType, + /** Current git branch name */ + @JsonProperty("branch") String branch, + /** Raw host string from the git remote URL */ + @JsonProperty("repositoryHost") String repositoryHost, + /** Head commit of the current git branch */ + @JsonProperty("headCommit") String headCommit, + /** Merge-base commit SHA */ + @JsonProperty("baseCommit") String baseCommit, + /** Name of the client that created the session */ + @JsonProperty("clientName") String clientName +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkspacesApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkspacesApi.java index 71a3d1ea1b..c65bd3854d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkspacesApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkspacesApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -31,7 +32,7 @@ public final class SessionWorkspacesApi { } /** - * Identifies the target session. + * Gets current workspace metadata for the session. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -42,7 +43,7 @@ public CompletableFuture getWorkspace() { } /** - * Workspace metadata fields to update. + * Updates workspace metadata for a local session and returns the refreshed workspace. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -58,7 +59,7 @@ public CompletableFuture updateMetadata(S } /** - * Optional session context used when creating a local workspace. + * Ensures a local session workspace exists and returns it. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -74,7 +75,7 @@ public CompletableFuture ensure(SessionWorkspaces } /** - * Identifies the target session. + * Lists files stored in the session workspace files directory. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -85,7 +86,7 @@ public CompletableFuture listFiles() { } /** - * Relative path of the workspace file to read. + * Reads a file from the session workspace files directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -101,7 +102,7 @@ public CompletableFuture readFile(SessionWorksp } /** - * Relative path and UTF-8 content for the workspace file to create or overwrite. + * Creates or overwrites a file in the session workspace files directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -117,7 +118,7 @@ public CompletableFuture createFile(SessionWorkspacesCreateFileParams para } /** - * Relative path of the workspace file or directory to inspect. + * Returns metadata for a file or directory in the session workspace files directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -133,7 +134,7 @@ public CompletableFuture statFile(SessionWorksp } /** - * Directory to create within the session workspace files directory. + * Creates a directory in the session workspace files directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -149,7 +150,7 @@ public CompletableFuture createDirectory(SessionWorkspacesCreateDirectoryP } /** - * File or directory to remove from the session workspace files directory. + * Removes a file or directory from the session workspace files directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -165,7 +166,7 @@ public CompletableFuture removePath(SessionWorkspacesRemovePathParams para } /** - * Source and destination paths for a rename within the session workspace files directory. + * Renames a file or directory within the session workspace files directory. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -181,7 +182,7 @@ public CompletableFuture renamePath(SessionWorkspacesRenamePathParams para } /** - * Identifies the target session. + * Lists workspace checkpoints in chronological order. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -192,7 +193,7 @@ public CompletableFuture listCheckpoints } /** - * Checkpoint number to read. + * Reads the content of a workspace checkpoint by number. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -208,7 +209,7 @@ public CompletableFuture readCheckpoint(S } /** - * Compaction summary checkpoint to persist. + * Adds a compaction summary checkpoint to the local session workspace. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -224,7 +225,7 @@ public CompletableFuture addSummary(SessionWo } /** - * Rollback point for local workspace summaries. + * Truncates local workspace compaction summaries after a rollback. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -240,7 +241,7 @@ public CompletableFuture truncateSumma } /** - * Identifies the target session. + * Reads the autopilot objective state file from the local session workspace. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -251,7 +252,7 @@ public CompletableFuture readAuto } /** - * Autopilot objective file content to persist. + * Writes the autopilot objective state file in the local session workspace. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -267,7 +268,7 @@ public CompletableFuture writeAu } /** - * Identifies the target session. + * Deletes the autopilot objective state file from the local session workspace. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -278,7 +279,7 @@ public CompletableFuture delete } /** - * Identifies the target session. + * Checks whether the local session workspace has an autopilot objective state file. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 @@ -289,7 +290,7 @@ public CompletableFuture autopi } /** - * Pasted content to save as a UTF-8 file in the session workspace. + * Saves pasted content as a UTF-8 file in the session workspace. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -305,7 +306,7 @@ public CompletableFuture saveLargePaste(S } /** - * Parameters for computing a workspace diff. + * Computes a diff for the session workspace. Never rejects for a busy session: a `session`-mode diff that cannot read the session's file-change captures falls back to an unstaged git diff with `isFallback: true` and reports why in `unavailableReason`. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. @@ -320,4 +321,19 @@ public CompletableFuture diff(SessionWorkspacesDiff return caller.invoke("session.workspaces.diff", _p, SessionWorkspacesDiffResult.class); } + /** + * Computes a diff for the session workspace. Never rejects for a busy session: a `session`-mode diff that cannot read the session's file-change captures falls back to an unstaged git diff with `isFallback: true` and reports why in `unavailableReason`. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture diff(SessionWorkspacesDiffRequest request) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(Objects.requireNonNull(request, "request")); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.workspaces.diff", _p, SessionWorkspacesDiffResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkspacesDiffRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkspacesDiffRequest.java new file mode 100644 index 0000000000..cf12c01e63 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkspacesDiffRequest.java @@ -0,0 +1,98 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Parameters for computing a workspace diff. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class SessionWorkspacesDiffRequest { + + /** Diff mode requested by the client. */ + @JsonProperty("mode") + private final WorkspaceDiffMode mode; + + /** When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. */ + @JsonProperty("ignoreWhitespace") + private Boolean ignoreWhitespace; + + /** Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. */ + @JsonProperty("includeContents") + private Boolean includeContents; + + /** + * Creates a request with its required inputs. + * + * @param mode Diff mode requested by the client. + */ + public SessionWorkspacesDiffRequest(WorkspaceDiffMode mode) { + this.mode = Objects.requireNonNull(mode, "mode"); + } + + /** + * Returns the {@code mode} property. + * + * @return Diff mode requested by the client. + */ + public WorkspaceDiffMode getMode() { + return mode; + } + + /** + * Returns the {@code ignoreWhitespace} property. + * + * @return When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + */ + public Boolean getIgnoreWhitespace() { + return ignoreWhitespace; + } + + /** + * Returns the {@code includeContents} property. + * + * @return Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + */ + public Boolean getIncludeContents() { + return includeContents; + } + + /** + * Sets the {@code ignoreWhitespace} property. + * + * @param value When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + * @return this request + */ + public SessionWorkspacesDiffRequest setIgnoreWhitespace(Boolean value) { + this.ignoreWhitespace = value; + return this; + } + + /** + * Sets the {@code includeContents} property. + * + * @param value Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + * @return this request + */ + public SessionWorkspacesDiffRequest setIncludeContents(Boolean value) { + this.includeContents = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsCreateWorkspaceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsCreateWorkspaceParams.java new file mode 100644 index 0000000000..04c54ddedb --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsCreateWorkspaceParams.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identity, state location and starting context for a workspace record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionsCreateWorkspaceParams( + /** Session ID the workspace record belongs to */ + @JsonProperty("sessionId") String sessionId, + /** Directory the session's state is written under when no session filesystem provider is configured. Ignored when a provider is configured; the provider's session state path is used instead. */ + @JsonProperty("sessionStatePath") String sessionStatePath, + /** `windows` (any letter case) selects Windows path rules. Any other value selects POSIX path rules. */ + @JsonProperty("convention") String convention, + /** Starting working-directory context. The record keeps `cwd`, `gitRoot`, `repository`, `hostType`, `branch`, and `clientName`. Other fields, including `repositoryHost`, `headCommit`, and `baseCommit`, are ignored. `hostType` must be `github` or `ado`. */ + @JsonProperty("context") SessionWorkingDirectoryContextWithClient context, + /** User-supplied display name for the workspace */ + @JsonProperty("name") String name +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsCreateWorkspaceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsCreateWorkspaceResult.java new file mode 100644 index 0000000000..b2cbe17721 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsCreateWorkspaceResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The workspace record that was written. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionsCreateWorkspaceResult( + /** The created workspace record, as JSON */ + @JsonProperty("workspaceJson") String workspaceJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsLoadWorkspaceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsLoadWorkspaceParams.java new file mode 100644 index 0000000000..bb4b83da26 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsLoadWorkspaceParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Where the session's state lives, as a root directory and the session ID under it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionsLoadWorkspaceParams( + /** Root directory every session's state directory sits under */ + @JsonProperty("sessionsHome") String sessionsHome, + /** Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsLoadWorkspaceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsLoadWorkspaceResult.java new file mode 100644 index 0000000000..f17c2c85d6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsLoadWorkspaceResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The workspace record on disk, omitted when the session has none. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionsLoadWorkspaceResult( + /** The workspace record, as JSON. Omitted when the record does not exist. */ + @JsonProperty("workspaceJson") String workspaceJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsUpdateWorkspaceFieldsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsUpdateWorkspaceFieldsParams.java new file mode 100644 index 0000000000..770e8269be --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionsUpdateWorkspaceFieldsParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SessionsUpdateWorkspaceFieldsParams( + /** Root directory every session's state directory sits under */ + @JsonProperty("sessionsHome") String sessionsHome, + /** Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. */ + @JsonProperty("sessionId") String sessionId, + /** Workspace-schema fields to merge into the record, as a JSON object. Fields the object omits keep their stored values, except stored keys outside the schema are not preserved and a stored `fork_count` is never replaced. */ + @JsonProperty("fieldsJson") String fieldsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditOperation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditOperation.java new file mode 100644 index 0000000000..ff6d7a5c69 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditOperation.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One atomic settings mutation. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum SettingsEditOperation { + /** The {@code set} variant. */ + SET("set"), + /** The {@code add-item} variant. */ + ADD_ITEM("add-item"), + /** The {@code remove-item} variant. */ + REMOVE_ITEM("remove-item"), + /** The {@code remove} variant. */ + REMOVE("remove"); + + private final String value; + SettingsEditOperation(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SettingsEditOperation fromValue(String value) { + for (SettingsEditOperation v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SettingsEditOperation value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditResult.java new file mode 100644 index 0000000000..ae05fb4237 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Outcome of an atomic user or repository settings edit. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SettingsEditResult( + /** Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. */ + @JsonProperty("status") SettingsEditStatus status +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditStatus.java new file mode 100644 index 0000000000..4bf228fc66 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditStatus.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Whether one atomic settings edit changed a file. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum SettingsEditStatus { + /** The {@code changed} variant. */ + CHANGED("changed"), + /** The {@code unchanged} variant. */ + UNCHANGED("unchanged"), + /** The {@code invalid} variant. */ + INVALID("invalid"); + + private final String value; + SettingsEditStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SettingsEditStatus fromValue(String value) { + for (SettingsEditStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SettingsEditStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderDescriptor.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderDescriptor.java index 659da543b3..64a287661b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderDescriptor.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderDescriptor.java @@ -13,7 +13,7 @@ import javax.annotation.processing.Generated; /** - * Catalog-only metadata for one SDK-provided skill. The complete SKILL.md is fetched separately and lazily. + * Authoritative catalog metadata for one SDK-provided skill. The skill's SKILL.md text is fetched separately and lazily. * * @since 1.0.0 */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderReadResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderReadResult.java index 96bb95206b..056b65f811 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderReadResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillProviderReadResult.java @@ -13,7 +13,7 @@ import javax.annotation.processing.Generated; /** - * Complete text-only SKILL.md content returned by an SDK session's skill provider. Related files and assets are not supported. + * Text-only SKILL.md content returned by an SDK session's skill provider. YAML frontmatter is optional: fields it omits come from the catalog descriptor, fields it declares must match the descriptor, and `allowed-tools` is read only from frontmatter. Related files and assets are not supported. * * @since 1.0.0 */ @@ -21,7 +21,7 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) record SkillProviderReadResult( - /** Complete SKILL.md text. The runtime enforces a 1 MiB UTF-8 byte limit. */ + /** SKILL.md text, with or without YAML frontmatter, or null when the provider has no skill with the requested name. The runtime enforces a 1 MiB UTF-8 byte limit. */ @JsonProperty("markdown") String markdown ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java index 03b9d85c1b..5dbde0dfd8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java @@ -27,7 +27,7 @@ public record SkillsDiscoverParams( /** Optional list of project directory paths to scan for project-scoped skills */ @JsonProperty("projectPaths") List projectPaths, - /** Optional list of additional skill directory paths to include */ + /** Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ @JsonProperty("skillDirectories") List skillDirectories, /** Optional skill scan paths to exclude from discovery. */ @JsonProperty("ignoredSkillsLocations") List ignoredSkillsLocations, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsGetDiscoveryPathsRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsGetDiscoveryPathsRequest.java new file mode 100644 index 0000000000..9b58939685 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsGetDiscoveryPathsRequest.java @@ -0,0 +1,131 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to enumerate. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class SkillsGetDiscoveryPathsRequest { + + /** Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** Optional skill scan paths to exclude from discovery. */ + @JsonProperty("ignoredSkillsLocations") + private List ignoredSkillsLocations; + + /** When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. */ + @JsonProperty("excludeHostSkills") + private Boolean excludeHostSkills; + + /** Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. */ + @JsonProperty("skillDirectories") + private List skillDirectories; + + /** + * Creates a request with its required inputs. + */ + public SkillsGetDiscoveryPathsRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code ignoredSkillsLocations} property. + * + * @return Optional skill scan paths to exclude from discovery. + */ + public List getIgnoredSkillsLocations() { + return ignoredSkillsLocations; + } + + /** + * Returns the {@code excludeHostSkills} property. + * + * @return When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + */ + public Boolean getExcludeHostSkills() { + return excludeHostSkills; + } + + /** + * Returns the {@code skillDirectories} property. + * + * @return Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + public List getSkillDirectories() { + return skillDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code ignoredSkillsLocations} property. + * + * @param value Optional skill scan paths to exclude from discovery. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setIgnoredSkillsLocations(List value) { + this.ignoredSkillsLocations = value; + return this; + } + + /** + * Sets the {@code excludeHostSkills} property. + * + * @param value When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setExcludeHostSkills(Boolean value) { + this.excludeHostSkills = value; + return this; + } + + /** + * Sets the {@code skillDirectories} property. + * + * @param value Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setSkillDirectories(List value) { + this.skillDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffLogLevelMigrationStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffLogLevelMigrationStatus.java new file mode 100644 index 0000000000..1538068712 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffLogLevelMigrationStatus.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the one-time staff log-level migration did. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum StaffLogLevelMigrationStatus { + /** The {@code ineligible} variant. */ + INELIGIBLE("ineligible"), + /** The {@code current} variant. */ + CURRENT("current"), + /** The {@code refreshed} variant. */ + REFRESHED("refreshed"); + + private final String value; + StaffLogLevelMigrationStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static StaffLogLevelMigrationStatus fromValue(String value) { + for (StaffLogLevelMigrationStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown StaffLogLevelMigrationStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffUpdateChannelMigrationStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffUpdateChannelMigrationStatus.java new file mode 100644 index 0000000000..a3cb8f83d7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffUpdateChannelMigrationStatus.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the one-time staff update-channel migration did. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum StaffUpdateChannelMigrationStatus { + /** The {@code ineligible} variant. */ + INELIGIBLE("ineligible"), + /** The {@code current} variant. */ + CURRENT("current"), + /** The {@code migrated} variant. */ + MIGRATED("migrated"), + /** The {@code completed} variant. */ + COMPLETED("completed"), + /** The {@code excluded-experimental} variant. */ + EXCLUDED_EXPERIMENTAL("excluded-experimental"); + + private final String value; + StaffUpdateChannelMigrationStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static StaffUpdateChannelMigrationStatus fromValue(String value) { + for (StaffUpdateChannelMigrationStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown StaffUpdateChannelMigrationStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UsageMetricsModelMetric.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UsageMetricsModelMetric.java index ed5f093054..879402975b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UsageMetricsModelMetric.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UsageMetricsModelMetric.java @@ -23,6 +23,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record UsageMetricsModelMetric( + /** Completeness of this model's reported AI-credit subtotal. Explicitly reported zero is complete, not unavailable. */ + @JsonProperty("aiCreditsStatus") AiCreditsStatus aiCreditsStatus, /** Request count and cost metrics for this model */ @JsonProperty("requests") UsageMetricsModelMetricRequests requests, /** Token usage metrics for this model */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UsageMetricsProviderModelMetric.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UsageMetricsProviderModelMetric.java new file mode 100644 index 0000000000..b4955e8c8d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UsageMetricsProviderModelMetric.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Usage for one recorded provider and model, without merging identical model IDs across providers. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record UsageMetricsProviderModelMetric( + /** Provider identity and product label captured when the call was dispatched; null when unknown. */ + @JsonProperty("provider") ModelProviderRef provider, + /** Model identity, or null for legacy aggregate-only usage. */ + @JsonProperty("modelId") String modelId, + /** Model display name captured at call time, when known. */ + @JsonProperty("modelDisplayName") String modelDisplayName, + /** Request, token, and cost totals for this provider/model. */ + @JsonProperty("metrics") UsageMetricsModelMetric metrics +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyParams.java new file mode 100644 index 0000000000..c81c4d218b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyParams.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * A single top-level setting subtree to validate and write. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsApplyTopKeyParams( + /** Canonical path of the setting the caller is editing. Currently informational only. */ + @JsonProperty("canonicalPath") List canonicalPath, + /** Top-level setting name to write. */ + @JsonProperty("topKey") String topKey, + /** Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. */ + @JsonProperty("value") Object value, + /** True to remove the top-level key instead of writing it. */ + @JsonProperty("delete") Boolean delete, + /** Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. */ + @JsonProperty("completeStaffUpdateChannelMigration") Boolean completeStaffUpdateChannelMigration +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyResult.java new file mode 100644 index 0000000000..85bdfd1d1a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Outcome of validating and writing one top-level setting subtree. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsApplyTopKeyResult( + /** `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. */ + @JsonProperty("status") String status, + /** Problems found, present only when `status` is `validation-error`. */ + @JsonProperty("issues") List issues, + /** Why the write failed, present only when `status` is `write-error`. */ + @JsonProperty("error") String error +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsBuildRuntimeParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsBuildRuntimeParams.java new file mode 100644 index 0000000000..7b95e8df04 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsBuildRuntimeParams.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The overrides and host context to resolve effective runtime settings from. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsBuildRuntimeParams( + /** Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. */ + @JsonProperty("overrides") Map overrides, + /** The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. */ + @JsonProperty("workingDirectory") String workingDirectory, + /** The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. */ + @JsonProperty("environment") Map environment, + /** The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. */ + @JsonProperty("platform") String platform +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsDiagnoseProblemsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsDiagnoseProblemsParams.java new file mode 100644 index 0000000000..de7ccae6c7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsDiagnoseProblemsParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The settings layers to diagnose. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsDiagnoseProblemsParams( + /** Layers to diagnose, in the precedence order the caller applies them. */ + @JsonProperty("sources") List sources +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsEditParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsEditParams.java new file mode 100644 index 0000000000..24f1cbd7f4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsEditParams.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * One atomic edit of a canonical setting in settings.json. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsEditParams( + /** Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. */ + @JsonProperty("configDir") String configDir, + /** Nonempty canonical path segments of the setting to edit, starting with its top-level key. */ + @JsonProperty("canonicalPath") List canonicalPath, + /** Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. */ + @JsonProperty("operation") SettingsEditOperation operation, + /** Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. */ + @JsonProperty("value") Object value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsParams.java new file mode 100644 index 0000000000..d9fca8e81a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects which settings file paths to resolve. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGetPathsParams( + /** Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. */ + @JsonProperty("repoRoot") String repoRoot +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsResult.java new file mode 100644 index 0000000000..2ed0ae2d5e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGetPathsResult( + /** The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. */ + @JsonProperty("userSettings") String userSettings, + /** The repository's checked-in settings file, or null when no repository root was supplied. */ + @JsonProperty("repoSettings") String repoSettings, + /** The repository's local, untracked settings file, or null when no repository root was supplied. */ + @JsonProperty("repoLocalSettings") String repoLocalSettings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetResult.java index c94e90fcc6..ac7b3cf933 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetResult.java @@ -15,7 +15,7 @@ import javax.annotation.processing.Generated; /** - * Per-key metadata for every known user setting (settings.json overlaid with the legacy config.json, config.json wins), including settings left at their default. Excludes repository- and enterprise-managed overrides. + * Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetUnknownKeysWarningParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetUnknownKeysWarningParams.java new file mode 100644 index 0000000000..a90c4a6853 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetUnknownKeysWarningParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGetUnknownKeysWarningParams( + /** The configuration directory, home directory and environment to resolve the settings document from. A host that scopes a session to its own Copilot home must pass that directory here, or the server's own home is inspected instead. */ + @JsonProperty("context") UserSettingsHostContext context +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGovernanceKeysResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGovernanceKeysResult.java new file mode 100644 index 0000000000..d4c0891e8f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGovernanceKeysResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Top-level user-setting keys grouped by who may govern them. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGovernanceKeysResult( + /** Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. */ + @JsonProperty("repo") List repo, + /** Top-level keys a repository may override through a Claude-compatible repository config. */ + @JsonProperty("claudeRepo") List claudeRepo, + /** Top-level keys an enterprise policy may fix through managed settings. */ + @JsonProperty("managed") List managed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsHostContext.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsHostContext.java new file mode 100644 index 0000000000..441023ed14 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsHostContext.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsHostContext( + /** The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. */ + @JsonProperty("configDir") String configDir, + /** The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. */ + @JsonProperty("homeDirectory") String homeDirectory, + /** The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. */ + @JsonProperty("environment") Map environment +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoParams.java new file mode 100644 index 0000000000..56af230edf --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * A repository to read settings from, and the user layer they are merged over. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadAndMergeRepoParams( + /** Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. */ + @JsonProperty("repoRoot") String repoRoot, + /** The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. */ + @JsonProperty("userSettings") Map userSettings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoResult.java new file mode 100644 index 0000000000..15b319f3d9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadAndMergeRepoResult( + /** The merged settings document, keyed by setting name. Equals the supplied user layer when the repository declares no settings. */ + @JsonProperty("settings") Map settings, + /** Why part of the repository document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did load are still merged, so a consumer should surface this and continue rather than treat it as a failure. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForConfigDirParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForConfigDirParams.java new file mode 100644 index 0000000000..0f745e7002 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForConfigDirParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory whose user settings to read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadForConfigDirParams( + /** Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. */ + @JsonProperty("configDir") String configDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForEditResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForEditResult.java new file mode 100644 index 0000000000..0a5b05d3c8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForEditResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Contents of settings.json as stored, for a caller about to rewrite it. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadForEditResult( + /** `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. */ + @JsonProperty("status") String status, + /** Parsed contents, present only when `status` is `ok`. */ + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoParams.java new file mode 100644 index 0000000000..2f809ae5b6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the repository whose checked-in settings to read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadRepoParams( + /** Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. */ + @JsonProperty("repoRoot") String repoRoot +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoResult.java new file mode 100644 index 0000000000..eb3f16cb85 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * A repository's settings as stored, together with any diagnostic raised while reading them. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadRepoResult( + /** The repository's settings document, keyed by setting name, with each value carried verbatim. Null when the repository declares no settings. */ + @JsonProperty("settings") Map settings, + /** Why part of the document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer should surface this and continue rather than treat it as a failure. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadWithWarningResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadWithWarningResult.java new file mode 100644 index 0000000000..1f9ba38d07 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadWithWarningResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The user's stored settings, together with any diagnostic raised while reading them. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadWithWarningResult( + /** The stored user settings document, keyed by setting name, with each value carried verbatim. Empty when the file could not be read at all. */ + @JsonProperty("settings") Map settings, + /** Why part of the document was ignored, phrased for display to the user. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer may surface this and continue rather than treat it as a failure. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserParams.java new file mode 100644 index 0000000000..740de3bc35 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeManagedAndUserParams( + /** The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. */ + @JsonProperty("managed") Object managed, + /** The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. */ + @JsonProperty("user") Object user +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserResult.java new file mode 100644 index 0000000000..c28bbddba3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The user layer folded over the managed layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeManagedAndUserResult( + /** The merged settings. An empty object when neither layer was supplied, so an unmanaged host with no user settings governs nothing. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueParams.java new file mode 100644 index 0000000000..30c47590c4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The user layer and the repository layer to fold together. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeRepoValueParams( + /** The user's settings, already resolved against any managed layer. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("userSettings") Object userSettings, + /** The repository's checked-in settings layer. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("repoSettings") Object repoSettings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueResult.java new file mode 100644 index 0000000000..136bf12f30 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The repository layer folded into the user layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeRepoValueResult( + /** The merged settings, with the per-entry managed control maps re-stamped from the runtime's ambient managed policy. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskParams.java new file mode 100644 index 0000000000..8c7fce5dd4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory whose settings document to clean. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateObsoleteOnDiskParams( + /** The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. */ + @JsonProperty("configDir") String configDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskResult.java new file mode 100644 index 0000000000..5e894430ed --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time obsolete-settings cleanup. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateObsoleteOnDiskResult( + /** What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not returned here: the document is written before this replies, so `user.settings.load` reads it authoritatively. */ + @JsonProperty("status") UserSettingsMigrateObsoleteOnDiskStatus status +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskStatus.java new file mode 100644 index 0000000000..38ef9d9a42 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskStatus.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the one-time obsolete-settings cleanup did to the document. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum UserSettingsMigrateObsoleteOnDiskStatus { + /** The {@code missing} variant. */ + MISSING("missing"), + /** The {@code invalid} variant. */ + INVALID("invalid"), + /** The {@code unchanged} variant. */ + UNCHANGED("unchanged"), + /** The {@code changed} variant. */ + CHANGED("changed"); + + private final String value; + UserSettingsMigrateObsoleteOnDiskStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static UserSettingsMigrateObsoleteOnDiskStatus fromValue(String value) { + for (UserSettingsMigrateObsoleteOnDiskStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown UserSettingsMigrateObsoleteOnDiskStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceParams.java new file mode 100644 index 0000000000..24220b8882 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffLogLevelOnceParams( + /** The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the migration is evaluated against the server's own home instead. */ + @JsonProperty("context") UserSettingsHostContext context, + /** When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. */ + @JsonProperty("cachedCompletedAt") String cachedCompletedAt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceResult.java new file mode 100644 index 0000000000..2ffc6ba552 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time staff log-level migration. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffLogLevelOnceResult( + /** What the migration did. Only `refreshed` can have changed the persisted settings. */ + @JsonProperty("status") StaffLogLevelMigrationStatus status, + /** When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. */ + @JsonProperty("completedAt") String completedAt, + /** The settings document as it stands after the migration, keyed by setting name. Present only for `refreshed`, and only when the document could be re-read cleanly. */ + @JsonProperty("settings") Map settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceParams.java new file mode 100644 index 0000000000..77a3287abe --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffUpdateChannelOnceParams( + /** The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. */ + @JsonProperty("configDir") String configDir, + /** The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. */ + @JsonProperty("homeDirectory") String homeDirectory, + /** The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. */ + @JsonProperty("environment") Map environment +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceResult.java new file mode 100644 index 0000000000..8d21eca4f1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time staff update-channel migration. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffUpdateChannelOnceResult( + /** What the migration did. Only `migrated` means the persisted settings changed. */ + @JsonProperty("status") StaffUpdateChannelMigrationStatus status, + /** When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. */ + @JsonProperty("completedAt") String completedAt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeParams.java new file mode 100644 index 0000000000..f43d774226 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Settings object whose key names should be canonicalized. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsNormalizeParams( + /** Free-form settings object, possibly using legacy or snake_case key names. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeResult.java new file mode 100644 index 0000000000..badb433c2a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Settings object with canonical key names. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsNormalizeResult( + /** The same settings with every legacy or snake_case key renamed to its canonical spelling. */ + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsPathResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsPathResult.java new file mode 100644 index 0000000000..5c4ac0d88e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsPathResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The on-disk location of the user's settings document. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsPathResult( + /** Absolute path to the settings file this runtime reads and writes. Normally `settings.json` under the Copilot configuration directory; an extensionless legacy `settings` file is reported instead when it exists and `settings.json` does not. */ + @JsonProperty("path") String path +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblem.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblem.java new file mode 100644 index 0000000000..057a5ac6a5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblem.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One setting that will not take effect, and why. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblem( + /** Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. */ + @JsonProperty("id") String id, + /** What is wrong in machine-readable form, for a caller that wants to branch rather than display. */ + @JsonProperty("kind") String kind, + /** Coarse grouping for the problem, for a caller that presents problems in sections. */ + @JsonProperty("category") String category, + /** The settings layer the problem was found in. */ + @JsonProperty("source") UserSettingsProblemLocation source, + /** The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. */ + @JsonProperty("rawKey") String rawKey, + /** Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. */ + @JsonProperty("explanation") String explanation +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemLocation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemLocation.java new file mode 100644 index 0000000000..454408eb8b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemLocation.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The settings layer a problem was found in. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblemLocation( + /** Which layer this is: `user`, `repo`, or `local`. */ + @JsonProperty("kind") String kind, + /** The caller-supplied display label for the layer. */ + @JsonProperty("label") String label, + /** Absolute path of the file backing this layer. */ + @JsonProperty("filePath") String filePath +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemSource.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemSource.java new file mode 100644 index 0000000000..1c471916c5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemSource.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * One already-loaded settings layer to diagnose. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblemSource( + /** Which layer this is: `user`, `repo`, or `local`. */ + @JsonProperty("kind") String kind, + /** Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. */ + @JsonProperty("label") String label, + /** Absolute path of the file backing this layer. */ + @JsonProperty("filePath") String filePath, + /** The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. */ + @JsonProperty("config") Map config, + /** True when the file itself failed to parse, so its keys could not be read at all. */ + @JsonProperty("invalid") Boolean invalid +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemsResult.java new file mode 100644 index 0000000000..6a5dcf5728 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemsResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The settings that will not take effect across the given layers. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblemsResult( + /** Each setting that will not take effect, and why. Empty when every layer is healthy. */ + @JsonProperty("problems") List problems +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceParams.java new file mode 100644 index 0000000000..98ec0b7fb3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsResetStaffModelSelectionOnceParams( + /** The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the reset is evaluated against the server's own home instead. */ + @JsonProperty("context") UserSettingsHostContext context, + /** Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. */ + @JsonProperty("staff") Boolean staff, + /** When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. */ + @JsonProperty("staffModelResetAt") String staffModelResetAt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceResult.java new file mode 100644 index 0000000000..90f9668f4f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceResult.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time staff model-selection reset. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsResetStaffModelSelectionOnceResult( + /** Whether the persisted model selection was cleared. Only `true` means the settings document changed and the host should adopt the returned settings. */ + @JsonProperty("didReset") Boolean didReset, + /** The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's own value back unchanged when nothing was reset. */ + @JsonProperty("resetAt") String resetAt, + /** The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or after it means the reset is already done. */ + @JsonProperty("cutoff") String cutoff, + /** The settings document as it stands after the reset, keyed by setting name. Present only when `didReset` is true. */ + @JsonProperty("settings") Map settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledParams.java new file mode 100644 index 0000000000..e8541c2841 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One hook to disable or re-enable. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsSetHookDisabledParams( + /** Path of the settings.json to rewrite. */ + @JsonProperty("settingsPath") String settingsPath, + /** Durable content-hash key of the hook, as `hooks.loadResources` reports it. */ + @JsonProperty("disableKey") String disableKey, + /** True adds the key to `disabledHooks`, false removes it. */ + @JsonProperty("disabled") Boolean disabled +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledResult.java new file mode 100644 index 0000000000..5548816405 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledResult.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Outcome of rewriting the `disabledHooks` setting. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsSetHookDisabledResult( + /** `ok` when the setting was written, `invalid` when settings.json could not be parsed and was left alone, `error` when the write itself failed. */ + @JsonProperty("status") String status, + /** Why the write failed. Absent when the status is `ok`. */ + @JsonProperty("errorMessage") String errorMessage +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java index ba19886c24..d56ecaa225 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java @@ -25,6 +25,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) public record UserSettingsSetParams( /** Partial user settings to write, as a free-form object keyed by setting name */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("settings") Object settings ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUnknownKeysWarningResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUnknownKeysWarningResult.java new file mode 100644 index 0000000000..404b8c57c0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUnknownKeysWarningResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The unrecognized top-level keys found in the user settings document, already phrased for display. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsUnknownKeysWarningResult( + /** The warning to show the user, naming the unrecognized keys and the file they were found in. Absent when every top-level key is recognized, and also when the document is missing or could not be read, because an unknown-key list taken from a document the runtime could not load would name keys that may not be there. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateParams.java new file mode 100644 index 0000000000..9aed7c14b3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateParams.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Names the user setting to merge into, and the partial object to merge. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsUpdateParams( + /** Top-level user-setting key to merge into, such as `extensions`. */ + @JsonProperty("key") String key, + /** Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("value") Object value, + /** Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. */ + @JsonProperty("configDir") String configDir, + /** Single-component name for the settings document at `/settings/.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. */ + @JsonProperty("subDir") String subDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateResult.java new file mode 100644 index 0000000000..2d13157a3b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The stored value of the user setting after the merge. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsUpdateResult( + /** The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. */ + @JsonProperty("value") Object value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateParams.java new file mode 100644 index 0000000000..3e69f4b138 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A single top-level setting subtree to validate. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsValidateParams( + /** Top-level setting name to validate. */ + @JsonProperty("topKey") String topKey, + /** Value to validate. Omitted when `delete` is true. */ + @JsonProperty("value") Object value, + /** True to validate a removal of this key. The current settings file is not read. */ + @JsonProperty("delete") Boolean delete +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateResult.java new file mode 100644 index 0000000000..730fb00195 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Outcome of validating one top-level setting subtree. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsValidateResult( + /** True when the subtree is valid. */ + @JsonProperty("ok") Boolean ok, + /** Problems found, empty when `ok` is true. */ + @JsonProperty("issues") List issues +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidationIssue.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidationIssue.java new file mode 100644 index 0000000000..68404e53a7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidationIssue.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * One problem found while validating a setting value. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsValidationIssue( + /** Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. */ + @JsonProperty("path") List path, + /** Human-readable description of the problem. */ + @JsonProperty("message") String message +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsWriteAllParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsWriteAllParams.java new file mode 100644 index 0000000000..e5929a8289 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsWriteAllParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The whole content to store in the user settings file. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsWriteAllParams( + /** The settings object to store. It replaces the file's entire content, so a key absent here is removed. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java index 5c53ad155f..e4001bb82e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java @@ -33,6 +33,7 @@ public record WorkflowExecuteParams( /** Opaque token identifying this workflow execution attempt. */ @JsonProperty("executionToken") String executionToken, /** Workflow input value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("args") Object args ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkspaceDiffContents.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkspaceDiffContents.java new file mode 100644 index 0000000000..7ffdaa1862 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkspaceDiffContents.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Complete text used to generate one session diff. These are display contents, with the same text decoding as the patch, not a file-restore contract. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record WorkspaceDiffContents( + /** Complete text before the session first changed the file. Omitted when the file did not exist; an empty string represents an existing empty file. */ + @JsonProperty("before") String before, + /** Complete current text read when computing the diff. Omitted for a deleted file; an empty string represents an existing empty file. */ + @JsonProperty("after") String after +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkspaceDiffFileChange.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkspaceDiffFileChange.java index e63b92b569..5ac0ec4efc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkspaceDiffFileChange.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkspaceDiffFileChange.java @@ -30,6 +30,27 @@ public record WorkspaceDiffFileChange( /** Original file path for renamed files. */ @JsonProperty("oldPath") String oldPath, /** Whether the diff content was omitted because it exceeded the per-file size limit. */ - @JsonProperty("isTruncated") Boolean isTruncated + @JsonProperty("isTruncated") Boolean isTruncated, + /** Full text used for this patch, only when includeContents was requested for session mode. Omitted for binary, oversized or unavailable contents, and for fallback results. Read isFallback and isTruncated before treating an absent value as a missing file. */ + @JsonProperty("contents") WorkspaceDiffContents contents ) { + + /** + * Creates a record with the components it had before later optional fields were added. + * + * @param path Path to the changed file, relative to the workspace root when the file lives under it. A file changed outside the workspace root keeps a `../`-relative path, or an absolute path when no relative path exists (for example a different Windows drive). + * @param diff Unified diff content for the file. Empty when the diff was truncated. + * @param changeType Type of change represented by this file diff. + * @param oldPath Original file path for renamed files. + * @param isTruncated Whether the diff content was omitted because it exceeded the per-file size limit. + */ + public WorkspaceDiffFileChange( + String path, + String diff, + WorkspaceDiffFileChangeType changeType, + String oldPath, + Boolean isTruncated + ) { + this(path, diff, changeType, oldPath, isTruncated, null); + } } diff --git a/java/sdk/src/main/java/com/github/copilot/AhpHost.java b/java/sdk/src/main/java/com/github/copilot/AhpHost.java index 9258289c85..92b400a205 100644 --- a/java/sdk/src/main/java/com/github/copilot/AhpHost.java +++ b/java/sdk/src/main/java/com/github/copilot/AhpHost.java @@ -5,6 +5,8 @@ package com.github.copilot; import com.github.copilot.generated.rpc.HostDisposeParams; +import com.github.copilot.generated.rpc.HostListSessionsParams; +import com.github.copilot.generated.rpc.HostListSessionsResult; import com.github.copilot.generated.rpc.HostPublishSessionParams; import com.github.copilot.generated.rpc.HostPublishSessionResult; import com.github.copilot.generated.rpc.HostStartResult; @@ -83,8 +85,8 @@ public CompletableFuture dispose() { } /** - * Publishes an exact resident session attached to the owning client, without - * invoking a factory or transferring session ownership. + * Durably advertises an exact attached session in the compute-scoped catalog, + * without invoking a factory or transferring session ownership. * * @param sessionId * resident session identity @@ -94,6 +96,15 @@ public CompletableFuture publishSession(String session return rpc.publishSession(new HostPublishSessionParams(info.hostId(), sessionId)); } + /** + * Lists all live and dormant catalog sessions advertised by this host. + * + * @return the advertised host sessions + */ + public CompletableFuture listSessions() { + return rpc.listSessions(new HostListSessionsParams(info.hostId())); + } + /** Disposes the listener and waits for acknowledged cleanup. */ @Override public void close() { diff --git a/java/sdk/src/main/java/com/github/copilot/AhpHostManager.java b/java/sdk/src/main/java/com/github/copilot/AhpHostManager.java index afd06e8f0e..7cefadcd5f 100644 --- a/java/sdk/src/main/java/com/github/copilot/AhpHostManager.java +++ b/java/sdk/src/main/java/com/github/copilot/AhpHostManager.java @@ -11,7 +11,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.copilot.generated.rpc.HostExitReason; import com.github.copilot.generated.rpc.HostExitedNotification; -import com.github.copilot.generated.rpc.HostStartParams; +import com.github.copilot.generated.rpc.HostStartRequest; import com.github.copilot.generated.rpc.ServerHostApi; import com.github.copilot.rpc.ResumeSessionConfig; import com.github.copilot.rpc.SessionConfig; @@ -99,8 +99,10 @@ CompletableFuture start(ServerHostApi rpc, AhpHostOptions options) { } var snapshot = host.options; return rpc - .start(new HostStartParams(host.id, snapshot.getLocalServer(), snapshot.getGithubEnvironment(), - snapshot.getCreateSession() != null, snapshot.getResumeSession() != null)) + .start(new HostStartRequest(host.id).setComputeId(snapshot.getComputeId()) + .setLocalServer(snapshot.getLocalServer()).setGitHubEnvironment(snapshot.getGithubEnvironment()) + .setSessionFactory(snapshot.getCreateSession() != null) + .setResumeFactory(snapshot.getResumeSession() != null)) .thenApply(info -> new AhpHost(info, rpc)).whenComplete((result, error) -> { if (error != null) { endHost(host, null); diff --git a/java/sdk/src/main/java/com/github/copilot/AhpHostOptions.java b/java/sdk/src/main/java/com/github/copilot/AhpHostOptions.java index 2ee29adab0..5a4ba6b11c 100644 --- a/java/sdk/src/main/java/com/github/copilot/AhpHostOptions.java +++ b/java/sdk/src/main/java/com/github/copilot/AhpHostOptions.java @@ -18,6 +18,7 @@ */ @CopilotExperimental public final class AhpHostOptions { + private String computeId; private HostLocalServerOptions localServer; private HostGitHubEnvironmentOptions githubEnvironment; private Function> createSession; @@ -33,6 +34,7 @@ public AhpHostOptions() { } AhpHostOptions(AhpHostOptions options) { + computeId = options.computeId; localServer = options.localServer; githubEnvironment = options.githubEnvironment; createSession = options.createSession; @@ -41,6 +43,28 @@ public AhpHostOptions() { onExit = options.onExit; } + /** + * Gets the durable catalog's compute identity. + * + * @return the stable compute identity, or {@code null} for the runtime default + */ + public String getComputeId() { + return computeId; + } + + /** + * Selects the same durable catalog for local and Mission Control hosting. Must + * agree with the GitHub environment's compute identity when both are supplied. + * + * @param computeId + * stable identity, or {@code null} for the runtime default + * @return these options + */ + public AhpHostOptions setComputeId(String computeId) { + this.computeId = computeId; + return this; + } + /** * Gets the local WebSocket transport settings. * diff --git a/java/sdk/src/main/java/com/github/copilot/CliServerManager.java b/java/sdk/src/main/java/com/github/copilot/CliServerManager.java index e742b242e5..0ccd2995e8 100644 --- a/java/sdk/src/main/java/com/github/copilot/CliServerManager.java +++ b/java/sdk/src/main/java/com/github/copilot/CliServerManager.java @@ -11,10 +11,17 @@ import java.net.Socket; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.List; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -34,6 +41,7 @@ final class CliServerManager { private static final Logger LOG = Logger.getLogger(CliServerManager.class.getName()); private static final int STDERR_READER_JOIN_TIMEOUT_MS = 5000; + static final int FORCE_KILL_TIMEOUT_SECONDS = 10; private final CopilotClientOptions options; private final StringBuilder stderrBuffer = new StringBuilder(); @@ -132,12 +140,20 @@ ProcessInfo startCliServer() throws IOException, InterruptedException { // Forward stderr to logger in background startStderrReader(process); - Integer detectedPort = null; - if (!options.isUseStdio()) { - detectedPort = waitForPortAnnouncement(process); + try { + Integer detectedPort = null; + if (!options.isUseStdio()) { + detectedPort = waitForPortAnnouncement(process); + } + return new ProcessInfo(process, detectedPort); + } catch (IOException | RuntimeException error) { + try { + cleanupCliProcess(process, captureDescendants(process), true); + } catch (RuntimeException cleanupError) { + error.addSuppressed(cleanupError); + } + throw error; } - - return new ProcessInfo(process, detectedPort); } /** @@ -206,11 +222,98 @@ private Integer waitForPortAnnouncement(Process process) throws IOException { } } - process.destroyForcibly(); throw new IOException("Timeout waiting for CLI to announce port"); } } + static void cleanupCliProcess(Process process, List descendants, boolean forceImmediately) { + if (!process.isAlive() && descendants.stream().noneMatch(ProcessHandle::isAlive)) { + return; + } + try { + if (terminateProcessTree(process, descendants, forceImmediately)) { + return; + } + if (!forceImmediately) { + if (terminateProcessTree(process, descendants, true)) { + return; + } + } + throw new IllegalStateException("CLI process tree did not terminate after shutdown: " + process.pid()); + } catch (InterruptedException error) { + Thread.currentThread().interrupt(); + throw new CompletionException("Interrupted while terminating the CLI process tree", error); + } catch (ExecutionException error) { + throw new CompletionException("Failed to await CLI process tree termination", error.getCause()); + } + } + + static List captureDescendants(Process process) { + return process.descendants().sorted(Comparator.comparingInt(CliServerManager::processDepth).reversed()) + .toList(); + } + + private static int processDepth(ProcessHandle process) { + int depth = 0; + var parent = process.parent(); + while (parent.isPresent()) { + depth++; + parent = parent.get().parent(); + } + return depth; + } + + private static boolean terminateProcessTree(Process process, List descendants, boolean force) + throws InterruptedException, ExecutionException { + long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(FORCE_KILL_TIMEOUT_SECONDS); + // Reap deepest children while their parents can still collect their exit. + // Killing the launcher first can orphan zombies in containers without an init. + for (var child : descendants) { + if (child.isAlive()) { + if (force) { + child.destroyForcibly(); + } else { + child.destroy(); + } + waitForProcessExit(child, deadline); + } + } + if (process.isAlive()) { + if (force) { + process.destroyForcibly(); + } else { + process.destroy(); + } + } + return waitForProcessTreeExit(process, descendants, deadline); + } + + private static boolean waitForProcessTreeExit(Process process, List descendants, long deadline) + throws InterruptedException, ExecutionException { + if (!process.waitFor(Math.max(0, deadline - System.nanoTime()), TimeUnit.NANOSECONDS)) { + return false; + } + for (var child : descendants) { + if (!waitForProcessExit(child, deadline)) { + return false; + } + } + return true; + } + + private static boolean waitForProcessExit(ProcessHandle process, long deadline) + throws InterruptedException, ExecutionException { + if (!process.isAlive()) { + return true; + } + try { + process.onExit().get(Math.max(0, deadline - System.nanoTime()), TimeUnit.NANOSECONDS); + return true; + } catch (TimeoutException error) { + return false; + } + } + String getStderrOutput() { synchronized (stderrBuffer) { return stderrBuffer.toString().trim(); @@ -252,9 +355,17 @@ private List resolveCliCommand(String cliPath, List args) { return result; } - // On Windows, use cmd /c to resolve the executable + // Own native executables directly so terminating the process cannot orphan + // a child behind cmd.exe. Batch shims still require the shell. String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win") && !new File(cliPath).isAbsolute()) { + String executable = resolveWindowsExecutable(cliPath); + if (executable != null) { + var result = new ArrayList(); + result.add(executable); + result.addAll(args); + return result; + } var result = new ArrayList(); result.add("cmd"); result.add("/c"); @@ -269,6 +380,59 @@ private List resolveCliCommand(String cliPath, List args) { return result; } + private String resolveWindowsExecutable(String cliPath) { + Path cwd = Path.of(options.getCwd() != null ? options.getCwd() : System.getProperty("user.dir")) + .toAbsolutePath(); + var directories = new ArrayList(); + var environment = options.getEnvironment() != null ? options.getEnvironment() : System.getenv(); + boolean hasDirectory = cliPath.contains("\\") || cliPath.contains("/"); + if (hasDirectory || environment.keySet().stream() + .noneMatch(key -> key.equalsIgnoreCase("NoDefaultCurrentDirectoryInExePath"))) { + directories.add(cwd.toString()); + } + if (!hasDirectory) { + String pathValue = environment.entrySet().stream().filter(entry -> entry.getKey().equalsIgnoreCase("PATH")) + .map(java.util.Map.Entry::getValue).findFirst().orElse(""); + directories.addAll(Arrays.asList(pathValue.split(File.pathSeparator))); + } + String pathExtensions = environment.entrySet().stream() + .filter(entry -> entry.getKey().equalsIgnoreCase("PATHEXT")).map(java.util.Map.Entry::getValue) + .findFirst().orElse(".COM;.EXE;.BAT;.CMD"); + String[] names = new File(cliPath).getName().contains(".") + ? new String[]{cliPath} + : Arrays.stream(pathExtensions.split(";")).map(extension -> cliPath + extension).toArray(String[]::new); + // Preserve invalid-command diagnostics even when implicit cwd search is + // disabled. + if (names.length > 0) { + Path.of(names[0]); + } + for (String directory : directories) { + if (directory.isBlank()) { + continue; + } + if (directory.startsWith("\"") && directory.endsWith("\"")) { + directory = directory.substring(1, directory.length() - 1); + } + Path searchDirectory; + try { + searchDirectory = cwd.resolve(directory); + } catch (InvalidPathException error) { + LOG.log(Level.FINE, "Skipping invalid PATH entry while resolving CLI executable", error); + continue; + } + for (String name : names) { + Path candidate = searchDirectory.resolve(name); + if (Files.isRegularFile(candidate)) { + String lowerName = name.toLowerCase(java.util.Locale.ROOT); + return lowerName.endsWith(".exe") || lowerName.endsWith(".com") + ? candidate.toAbsolutePath().toString() + : null; + } + } + } + return null; + } + void configureProcessEnvironment(ProcessBuilder pb) { if (options.getEnvironment() != null) { pb.environment().clear(); diff --git a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java index 4a6d33c8ce..de6081b39d 100644 --- a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java +++ b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java @@ -99,7 +99,7 @@ public final class CopilotClient implements AutoCloseable { public static final int AUTOCLOSEABLE_TIMEOUT_SECONDS = 10; private static final int RUNTIME_SHUTDOWN_TIMEOUT_SECONDS = 10; private static final int PROCESS_EXIT_TIMEOUT_SECONDS = 10; - private static final int FORCE_KILL_TIMEOUT_SECONDS = 10; + private static final int FORCE_KILL_TIMEOUT_SECONDS = CliServerManager.FORCE_KILL_TIMEOUT_SECONDS; /** * One-shot dispatcher used to run the owned-executor shutdown off any caller @@ -488,8 +488,10 @@ void setInProcessTransportFactory(InProcessTransportFactory factory) { private static InProcessTransport openInProcessTransport(CopilotClientOptions options) throws IOException { FfiRuntimeHost host = new FfiRuntimeHost(); try { - Path explicitEntrypoint = NativeRuntimeLoader.resolveConfiguredEntrypoint(); - host.start(explicitEntrypoint == null ? null : explicitEntrypoint.toString(), options); + String integrationId = System.getenv("GITHUB_COPILOT_INTEGRATION_ID"); + integrationId = integrationId == null || integrationId.isBlank() ? null : integrationId.trim(); + Path cliEntrypoint = NativeRuntimeLoader.resolveConfiguredEntrypoint(); + host.start(cliEntrypoint == null ? null : cliEntrypoint.toString(), integrationId, options); } catch (RuntimeException | Error e) { host.close(); throw e; @@ -585,9 +587,21 @@ private Connection startCoreBody() { installationConfirmationAdapter.registerHandlers(connectedRpc); } InstallationConfirmationAdapter connectedInstallationConfirmationAdapter = installationConfirmationAdapter; + // JsonRpcClient keeps one handler per method, so this one serves every request + // that honors cancellation. + connectedRpc.registerMethodHandler("$/cancelRequest", (rpcId, params) -> { + dispatcher.handleCancelRequest(params); + if (connectedInstallationConfirmationAdapter != null) { + connectedInstallationConfirmationAdapter.handleCancel(connectedRpc, params); + } + }); connectedRpc.setCloseHandler(() -> { ahpHosts.disconnect(connection.serverRpc().host); - sessions.values().forEach(CopilotSession::cancelPendingExternalTools); + sessions.values().forEach(session -> { + session.cancelPendingExternalTools(); + session.clearSkillProvider(); + }); + dispatcher.cancelSkillProviderCalls(); if (connectedLlmAdapter != null) { connectedLlmAdapter.cancelPending(); } @@ -652,7 +666,11 @@ private Connection startCoreBody() { if (drainBeforeCleanup) { serverManager.awaitStderrReader(); } - cleanupCliProcess(process, true); + try { + CliServerManager.cleanupCliProcess(process, CliServerManager.captureDescendants(process), true); + } catch (RuntimeException cleanupError) { + e.addSuppressed(cleanupError); + } if (!drainBeforeCleanup) { serverManager.awaitStderrReader(); } @@ -753,7 +771,7 @@ private static boolean isUnsupportedConnectMethod(JsonRpcException ex) { *
  • Requests runtime shutdown for SDK-owned CLI processes
  • *
  • Closes stdin for an owned stdio process and waits for its host * cleanup
  • - *
  • Closes the JSON-RPC connection, terminating an owned process if + *
  • Closes the JSON-RPC connection, terminating an owned process tree if * needed
  • * *

    @@ -793,7 +811,8 @@ public CompletableFuture stop() { } /** - * Forces an immediate stop of the client without graceful cleanup. + * Immediately stops the client, retires sessions and pending waits, and drops + * unadmitted callbacks. * * @return A future that completes when the client is stopped */ @@ -801,8 +820,8 @@ public CompletableFuture forceStop() { ahpHosts.disconnect(); disposed = true; var activeSessions = new ArrayList<>(sessions.values()); + activeSessions.forEach(CopilotSession::forceStopLocally); sessions.clear(); - activeSessions.forEach(CopilotSession::cancelPendingExternalTools); gitHubTokenProviders.clear(); // Dispatch the blocking shutdownOwnedExecutor() on a dedicated thread: // cleanupConnection() is chained off async work running on the owned @@ -830,6 +849,10 @@ private CompletableFuture cleanupConnection(boolean gracefulRuntimeShutdow return CompletableFuture.completedFuture(null); } + // Retain children before EOF or shutdown can let their launcher exit. + List descendants = connection.process == null + ? List.of() + : CliServerManager.captureDescendants(connection.process); CompletableFuture shutdownFuture = CompletableFuture.completedFuture(null); if (gracefulRuntimeShutdown && (connection.process != null || connection.runtimeHost != null)) { long runtimeShutdownStartNanos = System.nanoTime(); @@ -849,8 +872,10 @@ private CompletableFuture cleanupConnection(boolean gracefulRuntimeShutdow } return shutdownFuture.handleAsync((ignored, error) -> { + boolean preserveDetachedServices = gracefulRuntimeShutdown && error == null && !options.isUseStdio(); if (gracefulRuntimeShutdown && connection.process != null && options.isUseStdio()) { - awaitStdioProcessExit(connection.process); + boolean exitObserved = awaitOwnedRuntimeExit(connection); + preserveDetachedServices = exitObserved && error == null; } try { connection.rpc.close(); @@ -859,7 +884,11 @@ private CompletableFuture cleanupConnection(boolean gracefulRuntimeShutdow } if (connection.process != null) { - cleanupCliProcess(connection.process, !gracefulRuntimeShutdown || error != null); + // Successful shutdown leaves intentionally detached services alive. + // Keep the captured tree only for failed or forced shutdown. + CliServerManager.cleanupCliProcess(connection.process, + preserveDetachedServices ? List.of() : descendants, + !gracefulRuntimeShutdown || error != null); } if (connection.runtimeHost != null) { closeRuntimeHost(connection.runtimeHost); @@ -869,54 +898,24 @@ private CompletableFuture cleanupConnection(boolean gracefulRuntimeShutdow }).thenCompose(result -> result); } - private static void awaitStdioProcessExit(Process process) { + private static boolean awaitOwnedRuntimeExit(Connection connection) { + long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(PROCESS_EXIT_TIMEOUT_SECONDS); try { - // Host telemetry flushes after stdio EOF, not the shutdown RPC response. - // Keep the reader draining stdout until the child has finished. - process.getOutputStream().close(); - if (!process.waitFor(PROCESS_EXIT_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { - LOG.fine("Process did not exit after stdin EOF within graceful shutdown timeout; terminating"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - LOG.log(Level.FINE, "Interrupted while waiting for process exit", e); - } catch (IOException e) { - LOG.log(Level.FINE, "Error closing process stdin", e); - } - } - - /** - * Returns true only when the child had already exited and no streams were - * destroyed. - */ - private static boolean cleanupCliProcess(Process process, boolean forceImmediately) { - try { - if (process.isAlive()) { - if (forceImmediately) { - process.destroyForcibly(); - if (!process.waitFor(FORCE_KILL_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { - LOG.fine("Process did not terminate within force kill timeout"); - } - return false; - } - - process.destroy(); - if (process.waitFor(FORCE_KILL_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { - return false; - } - - process.destroyForcibly(); - if (!process.waitFor(FORCE_KILL_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { - LOG.fine("Process did not terminate within force kill timeout"); - } + // Host telemetry flushes after stdin EOF, not the shutdown response. + connection.process.getOutputStream().close(); + if (!connection.rpc.awaitPeerEof(deadline - System.nanoTime(), TimeUnit.NANOSECONDS)) { + LOG.fine("Runtime transport did not reach EOF within graceful shutdown timeout; terminating tree"); return false; } + if (!connection.process.waitFor(Math.max(0, deadline - System.nanoTime()), TimeUnit.NANOSECONDS)) { + LOG.fine("Launcher did not exit after runtime EOF; terminating launcher"); + } return true; } catch (InterruptedException e) { Thread.currentThread().interrupt(); - LOG.log(Level.FINE, "Interrupted while killing process", e); - } catch (Exception e) { - LOG.log(Level.FINE, "Error killing process", e); + LOG.log(Level.FINE, "Interrupted while waiting for process exit", e); + } catch (IOException e) { + LOG.log(Level.FINE, "Error awaiting runtime exit after closing stdin", e); } return false; } @@ -961,6 +960,10 @@ public CompletableFuture createSession(SessionConfig config) { return CompletableFuture.failedFuture( new IllegalArgumentException("gitHubToken and gitHubTokenProvider are mutually exclusive")); } + if (config.getCloud() != null && config.getSkillProvider() != null) { + return CompletableFuture.failedFuture( + new IllegalArgumentException("Skill providers are not supported for cloud sessions.")); + } return ensureConnected().thenCompose(connection -> { long totalNanos = System.nanoTime(); // For cloud sessions, let the CLI/server assign the session id @@ -1029,7 +1032,7 @@ public CompletableFuture createSession(SessionConfig config) { if (options.getMode() == CopilotClientMode.EMPTY) { if (config.getAvailableTools() == null) { if (registeredIdHolder[0] != null) { - sessions.remove(registeredIdHolder[0]); + sessions.remove(registeredIdHolder[0], preRegisteredSessionHolder[0]); } throw new IllegalArgumentException( "CopilotClient is in Mode = EMPTY but the session config did not specify " @@ -1129,9 +1132,10 @@ public CompletableFuture createSession(SessionConfig config) { }).exceptionally(ex -> { if (preRegisteredSessionHolder[0] != null) { preRegisteredSessionHolder[0].cancelPendingExternalTools(); + preRegisteredSessionHolder[0].clearSkillProvider(); } if (registeredIdHolder[0] != null) { - sessions.remove(registeredIdHolder[0]); + sessions.remove(registeredIdHolder[0], preRegisteredSessionHolder[0]); } if (tokenRegistration != null) { tokenRegistration.close(); @@ -1189,6 +1193,14 @@ public CompletableFuture resumeSession(String sessionId, ResumeS } return ensureConnected().thenCompose(connection -> { long totalNanos = System.nanoTime(); + // Validate before registering so a rejected resume leaves any resident + // session and its skill provider in place. + if (options.getMode() == CopilotClientMode.EMPTY && config.getAvailableTools() == null) { + throw new IllegalArgumentException( + "CopilotClient is in Mode = EMPTY but the resume session config did not specify " + + "availableTools. Empty mode requires every session to explicitly opt into " + + "the tools it wants — e.g. setAvailableTools(new ToolSet().addBuiltIn(BuiltInTools.ISOLATED))."); + } // Register the session before the RPC call to avoid missing early events. long setupNanos = System.nanoTime(); CopilotSession replacedSession = sessions.get(sessionId); @@ -1217,15 +1229,8 @@ public CompletableFuture resumeSession(String sessionId, ResumeS request.setEnableGitHubTelemetryForwarding(true); } - // Empty mode: validate availableTools and set toolFilterPrecedence for resume - // path + // Empty mode: set toolFilterPrecedence and isolation defaults for resume path if (options.getMode() == CopilotClientMode.EMPTY) { - if (config.getAvailableTools() == null) { - throw new IllegalArgumentException( - "CopilotClient is in Mode = EMPTY but the resume session config did not specify " - + "availableTools. Empty mode requires every session to explicitly opt into " - + "the tools it wants — e.g. setAvailableTools(new ToolSet().addBuiltIn(BuiltInTools.ISOLATED))."); - } request.setToolFilterPrecedence("excluded"); if (request.getSkipEmbeddingRetrieval() == null) { request.setSkipEmbeddingRetrieval(true); @@ -1290,7 +1295,7 @@ public CompletableFuture resumeSession(String sessionId, ResumeS // re-key. String returnedId = response.sessionId(); if (returnedId != null && !returnedId.equals(sessionId)) { - sessions.remove(sessionId); + sessions.remove(sessionId, session); session.setActiveSessionId(returnedId); sessions.put(returnedId, session); } @@ -1313,15 +1318,11 @@ public CompletableFuture resumeSession(String sessionId, ResumeS }); }).exceptionally(ex -> { session.cancelPendingExternalTools(); - sessions.remove(sessionId); - // Also remove the re-keyed entry if the server returned a different ID - String activeId = session.getSessionId(); - if (!sessionId.equals(activeId)) { - sessions.remove(activeId); - } - if (replacedSession != null) { - sessions.putIfAbsent(sessionId, replacedSession); - } + session.clearSkillProvider(); + // A concurrent resume may own the ID now; undo only this attempt. + sessions.compute(sessionId, + (id, current) -> current == null || current == session ? replacedSession : current); + sessions.remove(session.getSessionId(), session); if (tokenRegistration != null) { tokenRegistration.close(); } @@ -1441,6 +1442,9 @@ CompletableFuture updateSessionOptionsForMode(CopilotSession session, Bool null, // envValueMode null, // allowAllMcpServerInstructions null, // skillDirectories + null, // agentDirectories + null, // instructionDirectories + null, // hookDirectories null, // ignoredSkillsLocations patchSkills, // includedBuiltinSkills null, // disabledSkills @@ -1500,12 +1504,13 @@ CompletableFuture updateSessionOptionsForMode(CopilotSession session, Bool * @see ConnectionState */ public ConnectionState getState() { - if (connectionFuture == null) + CompletableFuture future = connectionFuture; + if (future == null) return ConnectionState.DISCONNECTED; - if (connectionFuture.isCompletedExceptionally()) - return ConnectionState.ERROR; - if (!connectionFuture.isDone()) + if (!future.isDone()) return ConnectionState.CONNECTING; + if (future.isCompletedExceptionally()) + return ConnectionState.ERROR; return ConnectionState.CONNECTED; } @@ -1667,6 +1672,7 @@ public CompletableFuture deleteSession(String sessionId) { } CopilotSession session = sessions.remove(sessionId); if (session != null) { + session.clearSkillProvider(); session.releaseGitHubTokenProviderRegistration(); } })); diff --git a/java/sdk/src/main/java/com/github/copilot/CopilotSession.java b/java/sdk/src/main/java/com/github/copilot/CopilotSession.java index ddd46aa262..497bce7983 100644 --- a/java/sdk/src/main/java/com/github/copilot/CopilotSession.java +++ b/java/sdk/src/main/java/com/github/copilot/CopilotSession.java @@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -172,6 +173,7 @@ public final class CopilotSession implements AutoCloseable { private static final Logger LOG = Logger.getLogger(CopilotSession.class.getName()); private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); private final java.util.Set> structuredWaits = ConcurrentHashMap.newKeySet(); + private final Map, CompletableFuture> plainWaits = new ConcurrentHashMap<>(); /** * Fixed name of the runtime's built-in tool-search tool. A client can replace @@ -195,7 +197,7 @@ public final class CopilotSession implements AutoCloseable { private final SessionUiApi ui; private final JsonRpcClient rpc; private volatile SessionRpc sessionRpc; - private final Set> eventHandlers = new CopyOnWriteArraySet<>(); + private final Set eventHandlers = new CopyOnWriteArraySet<>(); private final AtomicReference> toolHandlers = new AtomicReference<>(Map.of()); private final Object setToolsLock = new Object(); private CompletableFuture setToolsTail = CompletableFuture.completedFuture(null); @@ -211,6 +213,7 @@ public final class CopilotSession implements AutoCloseable { private final AtomicReference exitPlanModeHandler = new AtomicReference<>(); private final AtomicReference autoModeSwitchHandler = new AtomicReference<>(); private final AtomicReference hooksHandler = new AtomicReference<>(); + private final AtomicReference skillProvider = new AtomicReference<>(); private volatile EventErrorHandler eventErrorHandler; private volatile EventErrorPolicy eventErrorPolicy = EventErrorPolicy.PROPAGATE_AND_LOG_ERRORS; private volatile Map>> transformCallbacks; @@ -218,8 +221,17 @@ public final class CopilotSession implements AutoCloseable { private volatile Executor executor; private volatile GitHubTokenProviderRegistry.Registration gitHubTokenProviderRegistration; - /** Tracks whether this session instance has been terminated via close(). */ + /** Tracks whether this session instance has been closed or force-stopped. */ private volatile boolean isTerminated = false; + private volatile boolean callbacksRetired = false; + + private static final class EventSubscription { + private final AtomicReference> handler; + + EventSubscription(Consumer handler) { + this.handler = new AtomicReference<>(handler); + } + } private static final class PendingExternalTool { private static final int WAITING = 0; @@ -660,19 +672,33 @@ public CompletableFuture sendAndWait(MessageOptions optio } }; - Closeable subscription = on(handler); + var result = new CompletableFuture(); + Closeable subscription; + synchronized (this) { + subscription = on(handler); + plainWaits.put(result, future); + } + result.whenComplete((value, error) -> plainWaits.remove(result)); - send(options).exceptionally(ex -> { + try { + send(options).exceptionally(ex -> { + try { + subscription.close(); + } catch (IOException e) { + LOG.log(Level.SEVERE, "Error closing subscription", e); + } + future.completeExceptionally(ex); + return null; + }); + } catch (RuntimeException error) { + plainWaits.remove(result); try { subscription.close(); - } catch (Exception e) { - LOG.log(Level.SEVERE, "Error closing subscription", e); + } catch (IOException closeError) { + error.addSuppressed(closeError); } - future.completeExceptionally(ex); - return null; - }); - - var result = new CompletableFuture(); + throw error; + } // Schedule timeout on the shared session-level scheduler. // Per Javadoc, timeoutMs <= 0 means "no timeout". @@ -691,7 +717,10 @@ public CompletableFuture sendAndWait(MessageOptions optio } catch (IOException closeEx) { e.addSuppressed(closeEx); } - result.completeExceptionally(e); + // Retirement owns completion when it has already shut down the scheduler. + if (!isTerminated) { + result.completeExceptionally(e); + } return result; } } @@ -775,7 +804,9 @@ public CompletableFuture sendAndWait(MessageOptions optio * the returned future completes exceptionally. Concurrent replacements on the * same session are applied in call order. Cancelling the returned future while * an earlier replacement is still in flight sends nothing; once the request is - * sent, an accepted replacement still installs its handlers. + * sent, an accepted replacement still installs its handlers unless the session + * closes first. Closing the session rejects queued replacements and prevents + * late acknowledgements from restoring retired handlers. *

    * The agent sees the new tools from its next model request, which can fall * within a turn in progress. A model request already in flight was made with @@ -803,7 +834,13 @@ public CompletableFuture setTools(List tools) { if (result.isCancelled()) { return CompletableFuture.completedFuture(null); } - return getRpc().tools.set(params).thenRun(() -> toolHandlers.set(replacementHandlers)); + ensureNotTerminated(); + return getRpc().tools.set(params).thenRun(() -> { + synchronized (CopilotSession.this) { + ensureNotTerminated(); + toolHandlers.set(replacementHandlers); + } + }); }); setToolsTail = operation.handle((ignored, error) -> null); } @@ -936,14 +973,17 @@ synchronized void event(SessionEvent event) { } } var state = new State(); - Closeable subscription = on(event -> { - if (event instanceof AssistantMessageEvent || event instanceof SessionIdleEvent - || event instanceof SessionErrorEvent - || event instanceof com.github.copilot.generated.UserMessageEvent) { - state.event(event); - } - }); - structuredWaits.add(result); + Closeable subscription; + synchronized (this) { + subscription = on(event -> { + if (event instanceof AssistantMessageEvent || event instanceof SessionIdleEvent + || event instanceof SessionErrorEvent + || event instanceof com.github.copilot.generated.UserMessageEvent) { + state.event(event); + } + }); + structuredWaits.add(result); + } ScheduledFuture timer; try { timer = timeoutMs > 0 @@ -1022,9 +1062,20 @@ synchronized void event(SessionEvent event) { * @see #setEventErrorPolicy(EventErrorPolicy) */ public Closeable on(Consumer handler) { - ensureNotTerminated(); - eventHandlers.add(handler); - return () -> eventHandlers.remove(handler); + java.util.Objects.requireNonNull(handler, "handler"); + EventSubscription subscription; + synchronized (this) { + ensureNotTerminated(); + subscription = eventHandlers.stream().filter(entry -> handler.equals(entry.handler.get())).findFirst() + .orElseGet(() -> new EventSubscription(handler)); + eventHandlers.add(subscription); + } + return () -> { + synchronized (this) { + subscription.handler.set(null); + eventHandlers.remove(subscription); + } + }; } /** @@ -1080,8 +1131,7 @@ public Closeable on(Class eventType, Consumer han handler.accept(eventType.cast(event)); } }; - eventHandlers.add(wrapper); - return () -> eventHandlers.remove(wrapper); + return on(wrapper); } /** @@ -1108,12 +1158,25 @@ public Closeable on(Class eventType, Consumer han * @see #setEventErrorPolicy(EventErrorPolicy) */ void dispatchEvent(SessionEvent event) { + if (callbacksRetired) { + return; + } // Handle broadcast request events (protocol v3) and passive in-memory state // updates (capabilities, open-canvases snapshot) before dispatching to user // handlers. Fire-and-forget: any RPC response is sent asynchronously. handleBroadcastEventAsync(event); - for (Consumer handler : eventHandlers) { + for (EventSubscription subscription : eventHandlers) { + Consumer handler; + synchronized (this) { + if (callbacksRetired) { + return; + } + handler = subscription.handler.get(); + } + if (handler == null) { + continue; + } try { handler.accept(event); } catch (Exception e) { @@ -1163,7 +1226,9 @@ private void handleBroadcastEventAsync(SessionEvent event) { if (tool == null) { return; // This client doesn't handle this tool; another client will } - executeToolAndRespondAsync(data.requestId(), data.toolName(), data.toolCallId(), data.arguments(), tool); + String agentId = toolEvent.getAgentId(); + executeToolAndRespondAsync(data.requestId(), data.toolName(), data.toolCallId(), data.arguments(), tool, + agentId == null || agentId.isEmpty() ? null : agentId); } else if (event instanceof ExternalToolCompletedEvent completedEvent) { var data = completedEvent.getData(); @@ -1270,7 +1335,7 @@ void populateToolSearchMetadata(String toolName, com.github.copilot.rpc.ToolInvo * {@code session.tools.handlePendingToolCall}. */ private void executeToolAndRespondAsync(String requestId, String toolName, String toolCallId, Object arguments, - ToolDefinition tool) { + ToolDefinition tool, String agentId) { var pending = new PendingExternalTool(); synchronized (this) { if (isTerminated || externalToolsClosed || pendingExternalTools.putIfAbsent(requestId, pending) != null) { @@ -1284,6 +1349,7 @@ private void executeToolAndRespondAsync(String requestId, String toolName, Strin : (arguments != null ? MAPPER.valueToTree(arguments) : null); var invocation = new com.github.copilot.rpc.ToolInvocation().setSessionId(sessionId) .setToolCallId(toolCallId).setToolName(toolName).setArguments(argumentsNode); + invocation.setAgentId(agentId).setRequestId(requestId); if (TOOL_SEARCH_TOOL_NAME.equals(toolName)) { try { @@ -1774,6 +1840,18 @@ void registerMcpAuthHandler(McpAuthHandler handler) { mcpAuthHandler.set(handler); } + void registerSkillProvider(SkillProvider provider) { + skillProvider.set(provider); + } + + SkillProvider getSkillProvider() { + return skillProvider.get(); + } + + void clearSkillProvider() { + skillProvider.set(null); + } + /** * Handles a permission request from the Copilot CLI. *

    @@ -2802,23 +2880,16 @@ private void ensureNotTerminated() { *

    * This destroys the session on the server, clears all event handlers, and * releases tool and permission handlers. After calling this method, the session - * cannot be used again. Subsequent calls to this method have no effect. + * cannot be used again. Subsequent calls to this method have no effect. Pending + * response waits fail when the session retires; ordinary callbacks remain + * active until the detach acknowledgement. */ @Override public void close() { - synchronized (this) { - if (isTerminated) { - return; // Already terminated - no-op - } - isTerminated = true; + if (!retire(false)) { + return; } - structuredWaits.forEach(wait -> wait - .completeExceptionally(new IllegalStateException("Session closed before structured output completed"))); - cancelPendingExternalTools(); - timeoutScheduler.shutdownNow(); - releaseGitHubTokenProviderRegistration(); - RuntimeException detachFailure = null; try { SessionDetachResponse response = rpc @@ -2833,21 +2904,94 @@ public void close() { Thread.currentThread().interrupt(); } detachFailure = new IllegalStateException("Failed to detach session " + sessionId, e); + } finally { + retireCallbacks(); + } + + if (detachFailure != null) { + throw detachFailure; } + } + + /** + * Retires a tracked session without an RPC or joining admitted user handlers. + */ + void forceStopLocally() { + retire(true); + } + private boolean retire(boolean force) { + List waitCompletions = new ArrayList<>(); + synchronized (this) { + if (isTerminated) { + if (force) { + retireCallbacks(); + } + return false; + } + isTerminated = true; + structuredWaits.forEach(wait -> waitCompletions.add(() -> wait + .completeExceptionally(new IllegalStateException("Session closed before response completed")))); + plainWaits.forEach((result, terminal) -> { + if (terminal.isDone()) { + // Preserve a received terminal outcome even if its scheduler handoff is queued. + waitCompletions.add(() -> terminal.whenComplete((value, error) -> { + if (error != null) { + result.completeExceptionally(error); + } else { + result.complete(value); + } + })); + } else { + waitCompletions.add(() -> result.completeExceptionally( + new IllegalStateException("Session closed before response completed"))); + } + }); + structuredWaits.clear(); + if (force) { + retireCallbacks(); + } + plainWaits.clear(); + } + + cancelPendingExternalTools(); + clearSkillProvider(); + timeoutScheduler.shutdownNow(); + releaseGitHubTokenProviderRegistration(); + if (!waitCompletions.isEmpty()) { + // Completion can run blocking user continuations; don't borrow a shared or user + // executor. + var completions = Executors.newCachedThreadPool(task -> { + var thread = new Thread(task, "copilot-session-retirement"); + thread.setDaemon(true); + return thread; + }); + try { + waitCompletions.forEach(completions::execute); + } finally { + completions.shutdown(); + } + } + return true; + } + + private synchronized void retireCallbacks() { + callbacksRetired = true; + eventHandlers.forEach(subscription -> subscription.handler.set(null)); eventHandlers.clear(); toolHandlers.set(Map.of()); commandHandlers.clear(); + bearerTokenProviders.clear(); permissionHandler.set(null); + mcpAuthHandler.set(null); userInputHandler.set(null); elicitationHandler.set(null); exitPlanModeHandler.set(null); autoModeSwitchHandler.set(null); hooksHandler.set(null); - - if (detachFailure != null) { - throw detachFailure; - } + skillProvider.set(null); + eventErrorHandler = null; + transformCallbacks = null; } // ===== Internal response types for agent API ===== diff --git a/java/sdk/src/main/java/com/github/copilot/InstallationConfirmationAdapter.java b/java/sdk/src/main/java/com/github/copilot/InstallationConfirmationAdapter.java index 57d5ab26fe..99eddbe545 100644 --- a/java/sdk/src/main/java/com/github/copilot/InstallationConfirmationAdapter.java +++ b/java/sdk/src/main/java/com/github/copilot/InstallationConfirmationAdapter.java @@ -47,7 +47,6 @@ final class InstallationConfirmationAdapter { void registerHandlers(JsonRpcClient rpc) { rpc.registerMethodHandler("installations.confirm", (rpcId, params) -> handleConfirm(rpc, rpcId, params)); - rpc.registerMethodHandler("$/cancelRequest", (rpcId, params) -> handleCancel(rpc, params)); } void closePending() { @@ -80,7 +79,10 @@ private void handleConfirm(JsonRpcClient rpc, String rpcId, JsonNode params) { } } - private void handleCancel(JsonRpcClient rpc, JsonNode params) { + /** + * Cancels the confirmation named by a {@code $/cancelRequest} notification. + */ + void handleCancel(JsonRpcClient rpc, JsonNode params) { if (params == null || !params.has("id") || !params.get("id").canConvertToLong() || !params.get("id").isIntegralNumber()) { return; diff --git a/java/sdk/src/main/java/com/github/copilot/JsonRpcClient.java b/java/sdk/src/main/java/com/github/copilot/JsonRpcClient.java index fc10946829..310733aab8 100644 --- a/java/sdk/src/main/java/com/github/copilot/JsonRpcClient.java +++ b/java/sdk/src/main/java/com/github/copilot/JsonRpcClient.java @@ -14,8 +14,10 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -53,6 +55,8 @@ class JsonRpcClient implements AutoCloseable { private final Map> pendingRequests = new ConcurrentHashMap<>(); private final Map> notificationHandlers = new ConcurrentHashMap<>(); private final ExecutorService readerExecutor; + private final CountDownLatch readerExited = new CountDownLatch(1); + private boolean peerEof; private final Object closeHandlerLock = new Object(); private volatile boolean running = true; private boolean closeNotified; @@ -213,12 +217,20 @@ public void sendResponse(Object id, Object result) throws IOException { * Sends a JSON-RPC error response to a server request. */ public void sendErrorResponse(Object id, int code, String message) throws IOException { + sendErrorResponse(id, code, message, null); + } + + /** + * Sends a JSON-RPC error response to a server request with optional data. + */ + public void sendErrorResponse(Object id, int code, String message, Object data) throws IOException { var response = new JsonRpcResponse(); response.setJsonrpc("2.0"); response.setId(id); var error = new JsonRpcError(); error.setCode(code); error.setMessage(message); + error.setData(data); response.setError(error); sendMessage(response); } @@ -284,6 +296,7 @@ private void startReader() { while (inHeaders) { int b = bis.read(); if (b == -1) { + peerEof = true; return; } @@ -319,6 +332,7 @@ private void startReader() { while (read < contentLength) { int result = bis.read(buffer, read, contentLength - read); if (result == -1) { + peerEof = true; return; } read += result; @@ -334,11 +348,19 @@ private void startReader() { LOG.log(Level.SEVERE, "Error in JSON-RPC reader", e); } } finally { - notifyClose(); + try { + notifyClose(); + } finally { + readerExited.countDown(); + } } }); } + boolean awaitPeerEof(long timeout, TimeUnit unit) throws InterruptedException { + return readerExited.await(Math.max(0, timeout), unit) && peerEof; + } + void setCloseHandler(Runnable handler) { boolean runNow; synchronized (closeHandlerLock) { diff --git a/java/sdk/src/main/java/com/github/copilot/RpcHandlerDispatcher.java b/java/sdk/src/main/java/com/github/copilot/RpcHandlerDispatcher.java index 0dd8a5dc98..888ba538da 100644 --- a/java/sdk/src/main/java/com/github/copilot/RpcHandlerDispatcher.java +++ b/java/sdk/src/main/java/com/github/copilot/RpcHandlerDispatcher.java @@ -8,9 +8,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Map; +import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,6 +53,7 @@ *

  • Lifecycle events
  • * */ +@AllowCopilotExperimental final class RpcHandlerDispatcher { private static final Logger LOG = Logger.getLogger(RpcHandlerDispatcher.class.getName()); @@ -57,6 +63,7 @@ final class RpcHandlerDispatcher { private final LifecycleEventDispatcher lifecycleDispatcher; private final Executor executor; private final GitHubTokenProviderRegistry gitHubTokenProviders; + private final Map> skillProviderCancellations = new ConcurrentHashMap<>(); /** * Creates a dispatcher with session registry and lifecycle dispatcher. @@ -101,6 +108,144 @@ void registerHandlers(JsonRpcClient rpc) { (requestId, params) -> handleProviderTokenGetToken(rpc, requestId, params)); rpc.registerMethodHandler("gitHubToken.getToken", (requestId, params) -> handleGitHubTokenGetToken(rpc, requestId, params)); + rpc.registerMethodHandler("skillProvider.list", + (requestId, params) -> handleSkillProviderList(rpc, requestId, params)); + rpc.registerMethodHandler("skillProvider.read", + (requestId, params) -> handleSkillProviderRead(rpc, requestId, params)); + } + + // The generated skillProvider.* records are package-private because the + // methods are internal, so these handlers read params as JSON. + private void handleSkillProviderList(JsonRpcClient rpc, String requestId, JsonNode params) { + handleSkillProviderRequest(rpc, requestId, params, "skillProvider.list", "listSkills", + (provider, request) -> provider.listSkills(), + skills -> Map.of("skills", skills != null ? skills : Collections.emptyList())); + } + + private void handleSkillProviderRead(JsonRpcClient rpc, String requestId, JsonNode params) { + handleSkillProviderRequest(rpc, requestId, params, "skillProvider.read", "readSkill", + (provider, request) -> provider.readSkill(textParam(request, "name")), markdown -> { + // Write an explicit null: the runtime requires the field and reads null as "not + // found". + var result = MAPPER.createObjectNode(); + if (markdown == null) { + result.putNull("markdown"); + } else { + result.put("markdown", markdown); + } + return result; + }); + } + + private static String textParam(JsonNode params, String field) { + JsonNode value = params != null ? params.get(field) : null; + return value != null && !value.isNull() ? value.asText() : null; + } + + private void handleSkillProviderRequest(JsonRpcClient rpc, String requestId, JsonNode params, String method, + String operation, BiFunction> call, + Function toResult) { + final long requestIdLong = parseRequestId(requestId, method); + if (requestIdLong == -1) { + return; + } + // Registered on the reader thread so a later $/cancelRequest always finds it. + var cancellation = new CompletableFuture(); + skillProviderCancellations.put(requestIdLong, cancellation); + runAsync(() -> { + String failure = "Skill provider " + operation + " failed"; + String sessionId = null; + try { + sessionId = textParam(params, "sessionId"); + SkillProvider provider = findSkillProvider(sessionId); + if (provider == null) { + skillProviderCancellations.remove(requestIdLong, cancellation); + sendSkillProviderError(rpc, requestIdLong, "No skill provider for session: " + sessionId, sessionId, + null); + return; + } + CompletableFuture future = cancellation.isDone() + ? CompletableFuture.failedFuture(new CancellationException()) + : call.apply(provider, params); + if (future == null) { + future = CompletableFuture + .failedFuture(new IllegalStateException(operation + " returned a null future")); + } + final CompletableFuture providerFuture = future; + final String callSessionId = sessionId; + cancellation.thenRun(() -> providerFuture.cancel(true)); + providerFuture.whenComplete((value, error) -> { + skillProviderCancellations.remove(requestIdLong, cancellation); + if (cancellation.isDone()) { + sendSkillProviderCancelled(rpc, requestIdLong); + } else if (error != null) { + sendSkillProviderError(rpc, requestIdLong, failure, callSessionId, error); + } else { + sendSkillProviderResult(rpc, requestIdLong, method, failure, callSessionId, + () -> toResult.apply(value)); + } + }); + } catch (Exception error) { + skillProviderCancellations.remove(requestIdLong, cancellation); + sendSkillProviderError(rpc, requestIdLong, failure, sessionId, error); + } + }); + } + + /** + * Cancels the skill provider call named by a {@code $/cancelRequest} + * notification, if it is still in flight. + */ + void handleCancelRequest(JsonNode params) { + JsonNode id = params != null ? params.get("id") : null; + if (id == null || !id.isIntegralNumber() || !id.canConvertToLong()) { + return; + } + CompletableFuture cancellation = skillProviderCancellations.get(id.asLong()); + if (cancellation != null) { + cancellation.complete(null); + } + } + + /** Cancels every in-flight skill provider call when the connection closes. */ + void cancelSkillProviderCalls() { + skillProviderCancellations.values().forEach(cancellation -> cancellation.complete(null)); + } + + private SkillProvider findSkillProvider(String sessionId) { + CopilotSession session = sessionId != null ? sessions.get(sessionId) : null; + return session != null ? session.getSkillProvider() : null; + } + + private void sendSkillProviderResult(JsonRpcClient rpc, long requestId, String method, String failure, + String sessionId, Supplier result) { + try { + rpc.sendResponse(requestId, result.get()); + } catch (IOException error) { + LOG.log(Level.SEVERE, "Error sending " + method + " response", error); + } catch (RuntimeException error) { + sendSkillProviderError(rpc, requestId, failure, sessionId, error); + } + } + + private void sendSkillProviderCancelled(JsonRpcClient rpc, long requestId) { + try { + rpc.sendErrorResponse(requestId, -32800, "Request cancelled"); + } catch (IOException error) { + LOG.log(Level.FINE, "Error sending skill provider cancellation", error); + } + } + + private void sendSkillProviderError(JsonRpcClient rpc, long requestId, String message, String sessionId, + Throwable error) { + if (error != null) { + LOG.log(Level.WARNING, message + " (sessionId=" + sessionId + ")", error); + } + try { + rpc.sendErrorResponse(requestId, -32603, message); + } catch (IOException sendError) { + LOG.log(Level.SEVERE, "Error sending skill provider error", sendError); + } } private void handleGitHubTokenGetToken(JsonRpcClient rpc, String requestId, JsonNode params) { diff --git a/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java b/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java index 08101c1542..680ff0c160 100644 --- a/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java +++ b/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java @@ -153,6 +153,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess } request.setModel(config.getModel()); + request.setName(config.getName()); request.setClientName(config.getClientName()); request.setReasoningEffort(config.getReasoningEffort()); request.setReasoningSummary(config.getReasoningSummary()); @@ -196,10 +197,13 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setAgent(config.getAgent()); request.setInfiniteSessions(config.getInfiniteSessions()); request.setSkillDirectories(config.getSkillDirectories()); + request.setAgentDirectories(config.getAgentDirectories()); + request.setHookDirectories(config.getHookDirectories()); request.setInstructionDirectories(config.getInstructionDirectories()); request.setPluginDirectories(config.getPluginDirectories()); request.setLargeOutput(config.getLargeOutput()); request.setToolSearch(config.getToolSearch()); + request.setImageGeneration(config.getImageGeneration()); request.setMemory(config.getMemory()); request.setDisabledSkills(config.getDisabledSkills()); request.setDisabledMcpServers(config.getDisabledMcpServers()); @@ -215,6 +219,9 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess config.getEnableHostGitOperations().ifPresent(request::setEnableHostGitOperations); config.getEnableSessionStore().ifPresent(request::setEnableSessionStore); config.getEnableSkills().ifPresent(request::setEnableSkills); + if (config.getSkillProvider() != null) { + request.setHasSkillProvider(true); + } if (config.getEmbeddingCacheStorage() != null) { request.setEmbeddingCacheStorage(config.getEmbeddingCacheStorage()); } @@ -245,6 +252,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setFeatureFlags(config.getFeatureFlags()); request.setExpAssignments(config.getExpAssignments()); config.getEnableManagedSettings().ifPresent(request::setEnableManagedSettings); + config.getEnforceManagedModelDefaults().ifPresent(request::setEnforceManagedModelDefaults); request.setManagedSettings(config.getManagedSettings()); return request; @@ -335,6 +343,9 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo config.getEnableHostGitOperations().ifPresent(request::setEnableHostGitOperations); config.getEnableSessionStore().ifPresent(request::setEnableSessionStore); config.getEnableSkills().ifPresent(request::setEnableSkills); + if (config.getSkillProvider() != null) { + request.setHasSkillProvider(true); + } if (config.getEmbeddingCacheStorage() != null) { request.setEmbeddingCacheStorage(config.getEmbeddingCacheStorage()); } @@ -355,10 +366,13 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo request.setDefaultAgent(config.getDefaultAgent()); request.setAgent(config.getAgent()); request.setSkillDirectories(config.getSkillDirectories()); + request.setAgentDirectories(config.getAgentDirectories()); + request.setHookDirectories(config.getHookDirectories()); request.setInstructionDirectories(config.getInstructionDirectories()); request.setPluginDirectories(config.getPluginDirectories()); request.setLargeOutput(config.getLargeOutput()); request.setToolSearch(config.getToolSearch()); + request.setImageGeneration(config.getImageGeneration()); request.setMemory(config.getMemory()); request.setDisabledSkills(config.getDisabledSkills()); request.setDisabledMcpServers(config.getDisabledMcpServers()); @@ -389,6 +403,7 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo request.setFeatureFlags(config.getFeatureFlags()); request.setExpAssignments(config.getExpAssignments()); config.getEnableManagedSettings().ifPresent(request::setEnableManagedSettings); + config.getEnforceManagedModelDefaults().ifPresent(request::setEnforceManagedModelDefaults); request.setManagedSettings(config.getManagedSettings()); return request; @@ -435,6 +450,9 @@ static void configureSession(CopilotSession session, SessionConfig config) { if (config.getOnUserInputRequest() != null) { session.registerUserInputHandler(config.getOnUserInputRequest()); } + if (config.getSkillProvider() != null) { + session.registerSkillProvider(config.getSkillProvider()); + } if (config.getHooks() != null) { session.registerHooks(config.getHooks()); } @@ -487,6 +505,9 @@ static void configureSession(CopilotSession session, ResumeSessionConfig config) if (config.getOnUserInputRequest() != null) { session.registerUserInputHandler(config.getOnUserInputRequest()); } + if (config.getSkillProvider() != null) { + session.registerSkillProvider(config.getSkillProvider()); + } if (config.getHooks() != null) { session.registerHooks(config.getHooks()); } diff --git a/java/sdk/src/main/java/com/github/copilot/SkillProvider.java b/java/sdk/src/main/java/com/github/copilot/SkillProvider.java new file mode 100644 index 0000000000..d2907113f2 --- /dev/null +++ b/java/sdk/src/main/java/com/github/copilot/SkillProvider.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * Provides session-scoped skills to the Copilot runtime. + *

    + * A skill provider is registered through {@code SessionConfig} or + * {@code ResumeSessionConfig}. The runtime may invoke provider callbacks + * concurrently, so implementations should be thread-safe and avoid relying on + * callback ordering. + *

    + * When the runtime cancels a call, for example after its time limit or when the + * session disconnects, the SDK cancels the returned future with + * {@link CompletableFuture#cancel(boolean) cancel(true)} and the runtime + * ignores any later result. Cancellation does not interrupt running work; + * observe it with {@link CompletableFuture#isCancelled()} or a completion + * callback to stop early. + * + * @apiNote This API is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +public interface SkillProvider { + + /** + * Lists the skills currently available for the session. + * + * @return a future resolving to the provider's skill descriptors + */ + CompletableFuture> listSkills(); + + /** + * Reads the Markdown content for one skill. + * + * @param name + * the skill invocation name + * @return a future resolving to the skill Markdown, or {@code null} when the + * skill is not found + */ + CompletableFuture readSkill(String name); +} diff --git a/java/sdk/src/main/java/com/github/copilot/SkillProviderDescriptor.java b/java/sdk/src/main/java/com/github/copilot/SkillProviderDescriptor.java new file mode 100644 index 0000000000..04ac45845d --- /dev/null +++ b/java/sdk/src/main/java/com/github/copilot/SkillProviderDescriptor.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Catalog metadata for one skill supplied by a {@link SkillProvider}. + *

    + * The runtime lists these descriptors without fetching skill content, then + * calls {@link SkillProvider#readSkill(String)} when the skill is used. + * + * @param name + * the invocation and display name + * @param description + * the description shown in skill catalogs + * @param userInvocable + * whether users may invoke the skill directly, or {@code null} for + * the default ({@code true}) + * @param disableModelInvocation + * whether model invocation is disabled, or {@code null} for the + * default ({@code false}) + * @param argumentHint + * an optional freeform argument hint for slash-command catalogs + * @apiNote This API is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@JsonInclude(JsonInclude.Include.NON_NULL) +public record SkillProviderDescriptor(@JsonProperty("name") String name, + @JsonProperty("description") String description, @JsonProperty("userInvocable") Boolean userInvocable, + @JsonProperty("disableModelInvocation") Boolean disableModelInvocation, + @JsonProperty("argumentHint") String argumentHint) { +} diff --git a/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java b/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java index e28a573bc8..825a44497a 100644 --- a/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java +++ b/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java @@ -98,6 +98,23 @@ private static Path resolveLibraryPath() throws IOException { * {@code env_json} */ public void start(String entrypointPath, CopilotClientOptions options) { + start(entrypointPath, null, options); + } + + /** + * Starts the in-process runtime and opens a connection. + * + * @param entrypointPath + * optional explicit legacy CLI entrypoint passed in + * {@code argv_json} + * @param cliLoginSyncIntegrationId + * optional integration identifier used to synchronize login state + * with the Copilot CLI credential store + * @param options + * client options used to construct {@code argv_json} and + * {@code env_json} + */ + public void start(String entrypointPath, String cliLoginSyncIntegrationId, CopilotClientOptions options) { Objects.requireNonNull(options, "options must not be null"); if (disposed.get()) { throw new IllegalStateException("FfiRuntimeHost is already closed."); @@ -106,7 +123,7 @@ public void start(String entrypointPath, CopilotClientOptions options) { throw new IllegalStateException("FfiRuntimeHost has already been started."); } - byte[] argvJson = buildArgvJson(entrypointPath, options); + byte[] argvJson = buildArgvJson(entrypointPath, cliLoginSyncIntegrationId, options); byte[] envJson = buildEnvJson(options); int hostHandle = runHostStartOnBlockingThread(argvJson, envJson); if (hostHandle == 0) { @@ -275,7 +292,7 @@ private int runHostStartOnBlockingThread(byte[] argvJson, byte[] envJson) { } } - private static byte[] buildArgvJson(String entrypointPath, CopilotClientOptions options) { + static byte[] buildArgvJson(String entrypointPath, String cliLoginSyncIntegrationId, CopilotClientOptions options) { List argv = new ArrayList<>(); if (entrypointPath != null) { if (entrypointPath.toLowerCase().endsWith(".js")) { @@ -312,6 +329,9 @@ private static byte[] buildArgvJson(String entrypointPath, CopilotClientOptions if (options.isRemote()) { argv.add("--remote"); } + if (cliLoginSyncIntegrationId != null) { + argv.add("--cli-login-sync-integration-id=" + cliLoginSyncIntegrationId); + } String[] cliArgs = options.getCliArgs(); if (cliArgs != null && cliArgs.length > 0) { diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java b/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java index 1f6f1688fe..96820af0ef 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java @@ -4,6 +4,10 @@ package com.github.copilot.rpc; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -27,6 +31,30 @@ public class AgentInfo { @JsonProperty("model") private String model; + @JsonProperty("hooks") + private Map>> hooks; + + /** + * Gets declarative hook actions executed only while this agent is active. + * + * @return actions keyed by event name, or {@code null} if unset + */ + public Map>> getHooks() { + return hooks == null ? null : Collections.unmodifiableMap(hooks); + } + + /** + * Sets declarative hook actions scoped to this agent. + * + * @param hooks + * actions keyed by event name + * @return this instance for chaining + */ + public AgentInfo setHooks(Map>> hooks) { + this.hooks = hooks; + return this; + } + /** * Gets the unique identifier of the agent. * diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/AutoTier.java b/java/sdk/src/main/java/com/github/copilot/rpc/AutoTier.java index 092dc73026..cfeda84458 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/AutoTier.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/AutoTier.java @@ -12,26 +12,26 @@ * * @see CapiSessionOptions#setAutoTier(AutoTier) */ -public enum AutoTier { +public final class AutoTier { /** Prioritize efficiency. */ - EFFICIENCY("efficiency"), + public static final AutoTier EFFICIENCY = new AutoTier("efficiency"); /** Balance efficiency and intelligence. */ - BALANCE("balance"), + public static final AutoTier BALANCE = new AutoTier("balance"); /** Prioritize intelligence. */ - INTELLIGENCE("intelligence"), + public static final AutoTier INTELLIGENCE = new AutoTier("intelligence"); /** * Integrator-only preset that optimizes for latency. Not a first-party GitHub * Copilot product preference. */ - FAST("fast"); + public static final AutoTier FAST = new AutoTier("fast"); private final String value; - AutoTier(String value) { + private AutoTier(String value) { this.value = value; } @@ -52,7 +52,7 @@ public String getValue() { * the JSON string value * @return the matching tier, or {@code null} if value is {@code null} * @throws IllegalArgumentException - * if the value does not match a known routing tier + * if the value is not a routing identifier */ @JsonCreator public static AutoTier fromValue(String value) { @@ -64,6 +64,26 @@ public static AutoTier fromValue(String value) { return tier; } } - throw new IllegalArgumentException("Unknown AutoTier value: " + value); + return new AutoTier(com.github.copilot.generated.rpc.AutoTier.fromValue(value).getValue()); + } + + /** Returns the known convenience values. @return known routing tiers */ + public static AutoTier[] values() { + return new AutoTier[]{EFFICIENCY, BALANCE, INTELLIGENCE, FAST}; + } + + @Override + public boolean equals(Object other) { + return other instanceof AutoTier tier && value.equals(tier.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public String toString() { + return value; } } diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java b/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java index d8ab62af95..69b2bcaf3d 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java @@ -34,6 +34,9 @@ public final class CreateSessionRequest { @JsonProperty("sessionId") private String sessionId; + @JsonProperty("name") + private String name; + @JsonProperty("clientName") private String clientName; @@ -147,6 +150,12 @@ public final class CreateSessionRequest { @JsonProperty("skillDirectories") private List skillDirectories; + @JsonProperty("agentDirectories") + private List agentDirectories; + + @JsonProperty("hookDirectories") + private List hookDirectories; + @JsonProperty("instructionDirectories") private List instructionDirectories; @@ -159,6 +168,9 @@ public final class CreateSessionRequest { @JsonProperty("toolSearch") private ToolSearchConfig toolSearch; + @JsonProperty("imageGeneration") + private ImageGenerationConfig imageGeneration; + @JsonProperty("memory") private MemoryConfiguration memory; @@ -205,6 +217,10 @@ public final class CreateSessionRequest { @JsonInclude(JsonInclude.Include.NON_NULL) private Boolean enableSkills; + @JsonProperty("hasSkillProvider") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean hasSkillProvider; + @JsonProperty("embeddingCacheStorage") @JsonInclude(JsonInclude.Include.NON_NULL) private String embeddingCacheStorage; @@ -256,6 +272,10 @@ public final class CreateSessionRequest { @JsonInclude(JsonInclude.Include.NON_NULL) private Boolean enableManagedSettings; + @JsonProperty("enforceManagedModelDefaults") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean enforceManagedModelDefaults; + @JsonProperty("managedSettings") @JsonInclude(JsonInclude.Include.NON_NULL) private ManagedSettings managedSettings; @@ -280,6 +300,16 @@ public void setSessionId(String sessionId) { this.sessionId = sessionId; } + /** Gets the create-time session name. @return the session name */ + public String getName() { + return name; + } + + /** Sets the create-time session name. @param name the session name */ + public void setName(String name) { + this.name = name; + } + /** Gets the client name. @return the client name */ public String getClientName() { return clientName; @@ -712,6 +742,31 @@ public void setSkillDirectories(List skillDirectories) { this.skillDirectories = skillDirectories; } + /** Gets explicit agent discovery roots. @return the directories */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit agent discovery roots. @param agentDirectories the directories + */ + public void setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories; + } + + /** Gets explicit file-hook discovery roots. @return the directories */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit file-hook discovery roots. @param hookDirectories the + * directories + */ + public void setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories; + } + /** Gets instruction directories. @return the instruction directories */ public List getInstructionDirectories() { return instructionDirectories == null ? null : Collections.unmodifiableList(instructionDirectories); @@ -749,6 +804,19 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** Gets image generation config. @return the image generation config */ + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets image generation config. @param imageGeneration the image generation + * config + */ + public void setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + } + /** Sets tool-search config. @param toolSearch the tool-search config */ public void setToolSearch(ToolSearchConfig toolSearch) { this.toolSearch = toolSearch; @@ -956,6 +1024,23 @@ public void clearEnableSkills() { this.enableSkills = null; } + /** Gets skill-provider availability flag. @return the flag */ + public Boolean getHasSkillProvider() { + return hasSkillProvider; + } + + /** Sets skill-provider availability flag. @param hasSkillProvider the flag */ + public void setHasSkillProvider(boolean hasSkillProvider) { + this.hasSkillProvider = hasSkillProvider; + } + + /** + * Clears the hasSkillProvider setting, reverting to the default behavior. + */ + public void clearHasSkillProvider() { + this.hasSkillProvider = null; + } + /** Gets embedding cache storage mode. @return the mode */ public String getEmbeddingCacheStorage() { return embeddingCacheStorage; @@ -1220,6 +1305,21 @@ public void clearEnableManagedSettings() { this.enableManagedSettings = null; } + /** Gets managed model lock enforcement. @return the flag, or {@code null} */ + public Boolean getEnforceManagedModelDefaults() { + return enforceManagedModelDefaults; + } + + /** Sets managed model lock enforcement. @param enforce whether to enforce */ + public void setEnforceManagedModelDefaults(boolean enforce) { + this.enforceManagedModelDefaults = enforce; + } + + /** Clears managed model lock enforcement. */ + public void clearEnforceManagedModelDefaults() { + this.enforceManagedModelDefaults = null; + } + /** @return host-injected managed settings, or {@code null} when unset */ public ManagedSettings getManagedSettings() { return managedSettings; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java index 62de19b6a0..9f9c428ab4 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java @@ -36,6 +36,30 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class CustomAgentConfig { + @JsonProperty("hooks") + private Map>> hooks; + + /** + * Gets declarative hooks scoped to this agent. + * + * @return actions keyed by event name, or null when unset + */ + public Map>> getHooks() { + return hooks == null ? null : Collections.unmodifiableMap(hooks); + } + + /** + * Sets declarative hooks scoped to this agent. + * + * @param hooks + * actions keyed by event name + * @return this config for method chaining + */ + public CustomAgentConfig setHooks(Map>> hooks) { + this.hooks = hooks; + return this; + } + @JsonProperty("name") private String name; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ImageGenerationConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/ImageGenerationConfig.java new file mode 100644 index 0000000000..79b336b4da --- /dev/null +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ImageGenerationConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +package com.github.copilot.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; + +/** + * Experimental. This API may change or be removed in a future + * release. Opt in to image generation through an authorized Copilot image + * model. Omission disables on create/cold resume and preserves resident resume + * state. Not persisted: re-supply after runtime restart. Policy, permissions, + * offline mode, and tool filters still apply. BYOK image generation is not + * supported. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@CopilotExperimental +public class ImageGenerationConfig { + @JsonProperty("enabled") + private Boolean enabled; + + /** + * Gets the image generation opt-in. + * + * @return true to opt in, false to disable, or null when unset + */ + public Boolean getEnabled() { + return enabled; + } + + /** + * Enables or disables image generation. + * + * @param enabled + * the opt-in, or null when unset + * @return this config for method chaining + */ + public ImageGenerationConfig setEnabled(Boolean enabled) { + this.enabled = enabled; + return this; + } +} diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ManagedSettingsPermissions.java b/java/sdk/src/main/java/com/github/copilot/rpc/ManagedSettingsPermissions.java index 6755d959b3..f79277c1a1 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ManagedSettingsPermissions.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ManagedSettingsPermissions.java @@ -16,6 +16,9 @@ public final class ManagedSettingsPermissions { @JsonProperty("disableBypassPermissionsMode") private String disableBypassPermissionsMode; + @JsonProperty("disableAssistedPermissionsMode") + private Boolean disableAssistedPermissionsMode; + @JsonProperty("deny") private List deny; @@ -25,6 +28,9 @@ public final class ManagedSettingsPermissions { @JsonProperty("allow") private List allow; + @JsonProperty("limitTo") + private List limitTo; + /** @return the bypass-permissions policy, or {@code null} when unset */ public String getDisableBypassPermissionsMode() { return disableBypassPermissionsMode; @@ -44,6 +50,25 @@ public ManagedSettingsPermissions setDisableBypassPermissionsMode(String value) return this; } + /** + * @return whether Assisted Permissions are disabled, or {@code null} when unset + */ + public Boolean getDisableAssistedPermissionsMode() { + return disableAssistedPermissionsMode; + } + + /** + * Prevents Assisted Permissions from being activated when true. + * + * @param value + * whether Assisted Permissions are disabled + * @return this policy + */ + public ManagedSettingsPermissions setDisableAssistedPermissionsMode(Boolean value) { + this.disableAssistedPermissionsMode = value; + return this; + } + /** @return rules that deny matching operations, or {@code null} when unset */ public List getDeny() { return deny; @@ -88,4 +113,25 @@ public ManagedSettingsPermissions setAllow(List rules) { this.allow = rules == null ? null : new ArrayList<>(rules); return this; } + + /** + * @return the closed-world host boundary, or {@code null} when unset + */ + public List getLimitTo() { + return limitTo; + } + + /** + * Every network request must match this list, and multiple managed layers + * intersect their lists. A present empty list denies all hosts. + * + * @param rules + * host-only {@code Domain(hostname)}, {@code Domain(IP)}, or + * {@code Domain(*.example.com)} boundary rules + * @return this policy + */ + public ManagedSettingsPermissions setLimitTo(List rules) { + this.limitTo = rules == null ? null : new ArrayList<>(rules); + return this; + } } diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java index 4bc7de4803..adb7d7a9cd 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java @@ -15,6 +15,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.github.copilot.CopilotExperimental; +import com.github.copilot.SkillProvider; import com.github.copilot.generated.SessionEvent; import com.github.copilot.generated.rpc.DiagnosticsConfiguration; import com.github.copilot.generated.rpc.SessionLimitsConfig; @@ -83,6 +84,7 @@ public class ResumeSessionConfig { private Boolean enableHostGitOperations; private Boolean enableSessionStore; private Boolean enableSkills; + private SkillProvider skillProvider; private String embeddingCacheStorage; private boolean disableResume; private boolean streaming; @@ -95,11 +97,14 @@ public class ResumeSessionConfig { private DefaultAgentConfig defaultAgent; private String agent; private List skillDirectories; + private List agentDirectories; + private List hookDirectories; private List includedBuiltinSkills; private List instructionDirectories; private List pluginDirectories; private LargeToolOutputConfig largeOutput; private ToolSearchConfig toolSearch; + private ImageGenerationConfig imageGeneration; private MemoryConfiguration memory; private List disabledSkills; private List disabledMcpServers; @@ -117,6 +122,7 @@ public class ResumeSessionConfig { private String remoteSession; private CopilotExpAssignmentResponse expAssignments; private Boolean enableManagedSettings; + private Boolean enforceManagedModelDefaults; private Map featureFlags; private ManagedSettings managedSettings; @@ -1173,7 +1179,9 @@ public ResumeSessionConfig clearEnableOnDemandInstructionDiscovery() { } /** - * Gets whether file-based hooks are enabled. + * Gets whether repository-origin file hooks from {@code .github/hooks/} and + * trusted repository-configured roots are enabled. Does not control explicit + * {@link #getHookDirectories()} or callback hooks. * * @return an {@link java.util.Optional} containing {@code true} to enable file * hooks or {@code false} to disable them, or @@ -1311,6 +1319,35 @@ public ResumeSessionConfig clearEnableSkills() { return this; } + /** + * Gets the session-scoped skill provider for the resumed session. + * + * @return the skill provider, or {@code null} when not configured + * @apiNote This API is experimental and may change in a future version. + */ + @CopilotExperimental + @JsonIgnore + public SkillProvider getSkillProvider() { + return skillProvider; + } + + /** + * Sets the session-scoped skill provider for the resumed session. + *

    + * Skill provider registrations are not persisted; re-supply the provider when + * resuming. + * + * @param skillProvider + * the skill provider to expose to the runtime + * @return this config for method chaining + * @apiNote This API is experimental and may change in a future version. + */ + @CopilotExperimental + public ResumeSessionConfig setSkillProvider(SkillProvider skillProvider) { + this.skillProvider = skillProvider; + return this; + } + /** * Gets the embedding cache storage mode. * @@ -1627,7 +1664,11 @@ public ResumeSessionConfig setAgent(String agent) { } /** - * Gets the skill directories. + * Gets explicit discovery-only skill roots, not general filesystem grants. + * Available without configuration discovery, subject to skill/managed disables. + * Relative paths resolve once when supplied against the request's effective + * working directory; retained roots do not move when it changes. Null and + * omission are equivalent; an empty list clears only the SDK contribution. * * @return the list of skill directory paths */ @@ -1647,6 +1688,59 @@ public ResumeSessionConfig setSkillDirectories(List skillDirectories) { return this; } + /** + * Gets explicit discovery-only agent roots, separate from custom agent objects. + * No general filesystem grant. Available without configuration discovery, + * subject to source/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. + * + * @return the agent directory paths + */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit discovery-only agent roots. See {@link #getAgentDirectories()}. + * + * @param agentDirectories + * the agent directory paths + * @return this config for method chaining + */ + public ResumeSessionConfig setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories == null ? null : new ArrayList<>(agentDirectories); + return this; + } + + /** + * Gets explicit discovery-only file-hook roots, separate from callback hooks. + * No general filesystem grant. Available without configuration discovery or + * file-hook enablement (repository-origin hooks only), subject to hook/managed + * disables. Relative paths resolve once when supplied against the request's + * effective working directory; retained roots do not move. Null and omission + * are equivalent; an empty list clears only the SDK contribution. + * + * @return the file-hook directory paths + */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit discovery-only file-hook roots. See + * {@link #getHookDirectories()}. + * + * @param hookDirectories + * the file-hook directory paths + * @return this config for method chaining + */ + public ResumeSessionConfig setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories == null ? null : new ArrayList<>(hookDirectories); + return this; + } + /** * Gets the runtime-bundled skill allowlist. * @@ -1670,7 +1764,12 @@ public ResumeSessionConfig setIncludedBuiltinSkills(List includedBuiltin } /** - * Gets the additional directories to search for custom instruction files. + * Gets explicit discovery-only instruction roots using existing SDK formats. No + * general filesystem grant. Available without configuration discovery, subject + * to instruction/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. * * @return the list of instruction directory paths */ @@ -1741,6 +1840,29 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** + * Gets the non-persisted image generation opt-in. + * + * @return the image generation config, or null when unset + */ + @CopilotExperimental + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets the image generation opt-in. Re-supply after runtime restart. + * + * @param imageGeneration + * the image generation config + * @return this config for method chaining + */ + @CopilotExperimental + public ResumeSessionConfig setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + return this; + } + /** * Sets the tool-search configuration. * @@ -2171,6 +2293,28 @@ public ResumeSessionConfig setEnableManagedSettings(boolean enableManagedSetting return this; } + /** + * Gets whether locked managed model controls are enforced on resume. + * + * @return the explicit choice, or empty to use the runtime default + */ + @JsonIgnore + public Optional getEnforceManagedModelDefaults() { + return Optional.ofNullable(enforceManagedModelDefaults); + } + + /** + * Sets whether locked managed model controls are enforced after resume. + * + * @param enforceManagedModelDefaults + * whether to enforce locked managed model controls + * @return this config for method chaining + */ + public ResumeSessionConfig setEnforceManagedModelDefaults(boolean enforceManagedModelDefaults) { + this.enforceManagedModelDefaults = enforceManagedModelDefaults; + return this; + } + /** @return host-injected managed settings, or {@code null} when unset */ public ManagedSettings getManagedSettings() { return managedSettings; @@ -2244,6 +2388,7 @@ public ResumeSessionConfig clone() { copy.enableHostGitOperations = this.enableHostGitOperations; copy.enableSessionStore = this.enableSessionStore; copy.enableSkills = this.enableSkills; + copy.skillProvider = this.skillProvider; copy.embeddingCacheStorage = this.embeddingCacheStorage; copy.disableResume = this.disableResume; copy.streaming = this.streaming; @@ -2256,6 +2401,8 @@ public ResumeSessionConfig clone() { copy.defaultAgent = this.defaultAgent; copy.agent = this.agent; copy.skillDirectories = this.skillDirectories != null ? new ArrayList<>(this.skillDirectories) : null; + copy.agentDirectories = this.agentDirectories != null ? new ArrayList<>(this.agentDirectories) : null; + copy.hookDirectories = this.hookDirectories != null ? new ArrayList<>(this.hookDirectories) : null; copy.includedBuiltinSkills = this.includedBuiltinSkills != null ? new ArrayList<>(this.includedBuiltinSkills) : null; @@ -2265,6 +2412,7 @@ public ResumeSessionConfig clone() { copy.pluginDirectories = this.pluginDirectories != null ? new ArrayList<>(this.pluginDirectories) : null; copy.largeOutput = this.largeOutput; copy.toolSearch = this.toolSearch; + copy.imageGeneration = this.imageGeneration; copy.memory = this.memory; copy.disabledSkills = this.disabledSkills != null ? new ArrayList<>(this.disabledSkills) : null; copy.disabledMcpServers = this.disabledMcpServers != null ? new ArrayList<>(this.disabledMcpServers) : null; @@ -2283,6 +2431,7 @@ public ResumeSessionConfig clone() { copy.featureFlags = this.featureFlags != null ? new java.util.HashMap<>(this.featureFlags) : null; copy.expAssignments = this.expAssignments; copy.enableManagedSettings = this.enableManagedSettings; + copy.enforceManagedModelDefaults = this.enforceManagedModelDefaults; copy.managedSettings = this.managedSettings; return copy; } diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java index d25893ff19..9ca488e407 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java @@ -147,6 +147,10 @@ public final class ResumeSessionRequest { @JsonInclude(JsonInclude.Include.NON_NULL) private Boolean enableSkills; + @JsonProperty("hasSkillProvider") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean hasSkillProvider; + @JsonProperty("embeddingCacheStorage") @JsonInclude(JsonInclude.Include.NON_NULL) private String embeddingCacheStorage; @@ -193,6 +197,12 @@ public final class ResumeSessionRequest { @JsonProperty("skillDirectories") private List skillDirectories; + @JsonProperty("agentDirectories") + private List agentDirectories; + + @JsonProperty("hookDirectories") + private List hookDirectories; + @JsonProperty("instructionDirectories") private List instructionDirectories; @@ -205,6 +215,9 @@ public final class ResumeSessionRequest { @JsonProperty("toolSearch") private ToolSearchConfig toolSearch; + @JsonProperty("imageGeneration") + private ImageGenerationConfig imageGeneration; + @JsonProperty("memory") private MemoryConfiguration memory; @@ -261,6 +274,10 @@ public final class ResumeSessionRequest { @JsonInclude(JsonInclude.Include.NON_NULL) private Boolean enableManagedSettings; + @JsonProperty("enforceManagedModelDefaults") + @JsonInclude(JsonInclude.Include.NON_NULL) + private Boolean enforceManagedModelDefaults; + @JsonProperty("managedSettings") @JsonInclude(JsonInclude.Include.NON_NULL) private ManagedSettings managedSettings; @@ -764,6 +781,23 @@ public void clearEnableSkills() { this.enableSkills = null; } + /** Gets skill-provider availability flag. @return the flag */ + public Boolean getHasSkillProvider() { + return hasSkillProvider; + } + + /** Sets skill-provider availability flag. @param hasSkillProvider the flag */ + public void setHasSkillProvider(boolean hasSkillProvider) { + this.hasSkillProvider = hasSkillProvider; + } + + /** + * Clears the hasSkillProvider setting, reverting to the default behavior. + */ + public void clearHasSkillProvider() { + this.hasSkillProvider = null; + } + /** Gets embedding cache storage mode. @return the mode */ public String getEmbeddingCacheStorage() { return embeddingCacheStorage; @@ -968,6 +1002,31 @@ public void setSkillDirectories(List skillDirectories) { this.skillDirectories = skillDirectories; } + /** Gets explicit agent discovery roots. @return the directories */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit agent discovery roots. @param agentDirectories the directories + */ + public void setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories; + } + + /** Gets explicit file-hook discovery roots. @return the directories */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit file-hook discovery roots. @param hookDirectories the + * directories + */ + public void setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories; + } + /** Gets instruction directories. @return the instruction directories */ public List getInstructionDirectories() { return instructionDirectories == null ? null : Collections.unmodifiableList(instructionDirectories); @@ -1005,6 +1064,19 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** Gets image generation config. @return the image generation config */ + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets image generation config. @param imageGeneration the image generation + * config + */ + public void setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + } + /** Sets tool-search config. @param toolSearch the tool-search config */ public void setToolSearch(ToolSearchConfig toolSearch) { this.toolSearch = toolSearch; @@ -1250,6 +1322,21 @@ public void clearEnableManagedSettings() { this.enableManagedSettings = null; } + /** Gets managed model lock enforcement. @return the flag, or {@code null} */ + public Boolean getEnforceManagedModelDefaults() { + return enforceManagedModelDefaults; + } + + /** Sets managed model lock enforcement. @param enforce whether to enforce */ + public void setEnforceManagedModelDefaults(boolean enforce) { + this.enforceManagedModelDefaults = enforce; + } + + /** Clears managed model lock enforcement. */ + public void clearEnforceManagedModelDefaults() { + this.enforceManagedModelDefaults = null; + } + /** @return host-injected managed settings, or {@code null} when unset */ public ManagedSettings getManagedSettings() { return managedSettings; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java index 836b972ae2..a6828def9d 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java @@ -15,6 +15,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.github.copilot.CopilotExperimental; +import com.github.copilot.SkillProvider; import com.github.copilot.generated.SessionEvent; import com.github.copilot.generated.rpc.DiagnosticsConfiguration; import com.github.copilot.generated.rpc.SessionLimitsConfig; @@ -42,6 +43,7 @@ public class SessionConfig { private String sessionId; + private String name; private String clientName; private String model; private String reasoningEffort; @@ -83,11 +85,14 @@ public class SessionConfig { private String agent; private InfiniteSessionConfig infiniteSessions; private List skillDirectories; + private List agentDirectories; + private List hookDirectories; private List includedBuiltinSkills; private List instructionDirectories; private List pluginDirectories; private LargeToolOutputConfig largeOutput; private ToolSearchConfig toolSearch; + private ImageGenerationConfig imageGeneration; private MemoryConfiguration memory; private List disabledSkills; private List disabledMcpServers; @@ -101,6 +106,7 @@ public class SessionConfig { private Boolean enableHostGitOperations; private Boolean enableSessionStore; private Boolean enableSkills; + private SkillProvider skillProvider; private String embeddingCacheStorage; private ModelCapabilitiesOverride modelCapabilities; private Consumer onEvent; @@ -117,6 +123,7 @@ public class SessionConfig { private CloudSessionOptions cloud; private CopilotExpAssignmentResponse expAssignments; private Boolean enableManagedSettings; + private Boolean enforceManagedModelDefaults; private Map featureFlags; private ManagedSettings managedSettings; @@ -143,6 +150,31 @@ public SessionConfig setSessionId(String sessionId) { return this; } + /** + * Gets the create-time session name. + * + * @return the session name, or {@code null} if the session is unnamed + */ + public String getName() { + return name; + } + + /** + * Names the session at creation, as {@code session.name.set} would, and is + * validated the same way: non-empty, no leading or trailing whitespace, at most + * 100 UTF-16 units, no control characters, and no double quotes. A name also + * makes the session persist from the start, so it can be listed and resumed + * without ever running a turn. Local sessions only: cloud creation rejects it. + * + * @param name + * the session name + * @return this config instance for method chaining + */ + public SessionConfig setName(String name) { + this.name = name; + return this; + } + /** * Gets the client name used to identify the application using the SDK. * @@ -1232,7 +1264,11 @@ public SessionConfig setInfiniteSessions(InfiniteSessionConfig infiniteSessions) } /** - * Gets the skill directories. + * Gets explicit discovery-only skill roots, not general filesystem grants. + * Available without configuration discovery, subject to skill/managed disables. + * Relative paths resolve once when supplied against the request's effective + * working directory; retained roots do not move when it changes. Null and + * omission are equivalent; an empty list clears only the SDK contribution. * * @return the list of skill directory paths */ @@ -1256,6 +1292,59 @@ public SessionConfig setSkillDirectories(List skillDirectories) { return this; } + /** + * Gets explicit discovery-only agent roots, separate from custom agent objects. + * No general filesystem grant. Available without configuration discovery, + * subject to source/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. + * + * @return the agent directory paths + */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit discovery-only agent roots. See {@link #getAgentDirectories()}. + * + * @param agentDirectories + * the agent directory paths + * @return this config for method chaining + */ + public SessionConfig setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories == null ? null : new ArrayList<>(agentDirectories); + return this; + } + + /** + * Gets explicit discovery-only file-hook roots, separate from callback hooks. + * No general filesystem grant. Available without configuration discovery or + * file-hook enablement (repository-origin hooks only), subject to hook/managed + * disables. Relative paths resolve once when supplied against the request's + * effective working directory; retained roots do not move. Null and omission + * are equivalent; an empty list clears only the SDK contribution. + * + * @return the file-hook directory paths + */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit discovery-only file-hook roots. See + * {@link #getHookDirectories()}. + * + * @param hookDirectories + * the file-hook directory paths + * @return this config for method chaining + */ + public SessionConfig setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories == null ? null : new ArrayList<>(hookDirectories); + return this; + } + /** * Gets the runtime-bundled skill allowlist. * @@ -1279,7 +1368,12 @@ public SessionConfig setIncludedBuiltinSkills(List includedBuiltinSkills } /** - * Gets the additional directories to search for custom instruction files. + * Gets explicit discovery-only instruction roots using existing SDK formats. No + * general filesystem grant. Available without configuration discovery, subject + * to instruction/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. * * @return the list of instruction directory paths */ @@ -1350,6 +1444,29 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** + * Gets the non-persisted image generation opt-in. + * + * @return the image generation config, or null when unset + */ + @CopilotExperimental + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets the image generation opt-in. Re-supply after runtime restart. + * + * @param imageGeneration + * the image generation config + * @return this config for method chaining + */ + @CopilotExperimental + public SessionConfig setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + return this; + } + /** * Sets the tool-search override configuration. When {@code null}, the runtime * default tool-search behavior applies. @@ -1621,7 +1738,9 @@ public SessionConfig clearRefreshCustomInstructions() { } /** - * Gets whether file-based hooks are enabled. + * Gets whether repository-origin file hooks from {@code .github/hooks/} and + * trusted repository-configured roots are enabled. Does not control explicit + * {@link #getHookDirectories()} or callback hooks. * * @return an {@link java.util.Optional} containing {@code true} to enable file * hooks or {@code false} to disable them, or @@ -1759,6 +1878,35 @@ public SessionConfig clearEnableSkills() { return this; } + /** + * Gets the session-scoped skill provider. + * + * @return the skill provider, or {@code null} when not configured + * @apiNote This API is experimental and may change in a future version. + */ + @CopilotExperimental + @JsonIgnore + public SkillProvider getSkillProvider() { + return skillProvider; + } + + /** + * Sets the session-scoped skill provider. + *

    + * Re-supply this provider when resuming a session. Skill providers are not + * supported for cloud sessions. + * + * @param skillProvider + * the skill provider to expose to the runtime + * @return this config instance for method chaining + * @apiNote This API is experimental and may change in a future version. + */ + @CopilotExperimental + public SessionConfig setSkillProvider(SkillProvider skillProvider) { + this.skillProvider = skillProvider; + return this; + } + /** * Gets the embedding cache storage mode. * @@ -2262,6 +2410,29 @@ public SessionConfig setEnableManagedSettings(boolean enableManagedSettings) { return this; } + /** + * Gets whether locked managed model controls are enforced. + * + * @return the explicit choice, or empty to use the runtime default + */ + @JsonIgnore + public Optional getEnforceManagedModelDefaults() { + return Optional.ofNullable(enforceManagedModelDefaults); + } + + /** + * Sets whether locked managed model controls are enforced for this session. + * Conflicting model changes are rejected; overridable defaults remain mutable. + * + * @param enforceManagedModelDefaults + * whether to enforce locked managed model controls + * @return this config instance for method chaining + */ + public SessionConfig setEnforceManagedModelDefaults(boolean enforceManagedModelDefaults) { + this.enforceManagedModelDefaults = enforceManagedModelDefaults; + return this; + } + /** * Gets host-injected managed settings for this session. * @@ -2344,6 +2515,8 @@ public SessionConfig clone() { copy.agent = this.agent; copy.infiniteSessions = this.infiniteSessions; copy.skillDirectories = this.skillDirectories != null ? new ArrayList<>(this.skillDirectories) : null; + copy.agentDirectories = this.agentDirectories != null ? new ArrayList<>(this.agentDirectories) : null; + copy.hookDirectories = this.hookDirectories != null ? new ArrayList<>(this.hookDirectories) : null; copy.includedBuiltinSkills = this.includedBuiltinSkills != null ? new ArrayList<>(this.includedBuiltinSkills) : null; @@ -2353,6 +2526,7 @@ public SessionConfig clone() { copy.pluginDirectories = this.pluginDirectories != null ? new ArrayList<>(this.pluginDirectories) : null; copy.largeOutput = this.largeOutput; copy.toolSearch = this.toolSearch; + copy.imageGeneration = this.imageGeneration; copy.memory = this.memory; copy.disabledSkills = this.disabledSkills != null ? new ArrayList<>(this.disabledSkills) : null; copy.disabledMcpServers = this.disabledMcpServers != null ? new ArrayList<>(this.disabledMcpServers) : null; @@ -2366,6 +2540,7 @@ public SessionConfig clone() { copy.enableHostGitOperations = this.enableHostGitOperations; copy.enableSessionStore = this.enableSessionStore; copy.enableSkills = this.enableSkills; + copy.skillProvider = this.skillProvider; copy.embeddingCacheStorage = this.embeddingCacheStorage; copy.modelCapabilities = this.modelCapabilities; copy.onEvent = this.onEvent; @@ -2383,6 +2558,7 @@ public SessionConfig clone() { copy.featureFlags = this.featureFlags != null ? new java.util.HashMap<>(this.featureFlags) : null; copy.expAssignments = this.expAssignments; copy.enableManagedSettings = this.enableManagedSettings; + copy.enforceManagedModelDefaults = this.enforceManagedModelDefaults; copy.managedSettings = this.managedSettings; return copy; } diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ToolInvocation.java b/java/sdk/src/main/java/com/github/copilot/rpc/ToolInvocation.java index efe24fd6ae..a0a004176a 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ToolInvocation.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ToolInvocation.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.copilot.CopilotExperimental; import com.github.copilot.generated.rpc.CurrentToolMetadata; /** @@ -43,6 +44,8 @@ public final class ToolInvocation { private String toolName; private JsonNode argumentsNode; private List availableTools; + private String agentId; + private String requestId; /** * Gets the session ID where the tool was invoked. @@ -208,4 +211,71 @@ public ToolInvocation setAvailableTools(List availableTools this.availableTools = availableTools; return this; } + + /** + * Gets the sub-agent instance that issued this call. + *

    + * Experimental. This is the {@code agentId} of the sub-agent's + * session events. It is {@code null} for a root-agent call, for every call when + * the runtime does not attribute sub-agent tool calls, and for a call that did + * not arrive as an external tool request. + * + * @return the sub-agent instance id, or {@code null} when no sub-agent is named + * @since 1.0.15-preview.1 + */ + @CopilotExperimental + public String getAgentId() { + return agentId; + } + + /** + * Sets the sub-agent instance that issued this call. + *

    + * Note: This method is intended for internal SDK use. Users + * typically do not need to call this method directly. + * + * @param agentId + * the sub-agent instance id, or {@code null} when no sub-agent is + * named + * @return this invocation for method chaining + */ + @CopilotExperimental + public ToolInvocation setAgentId(String agentId) { + this.agentId = agentId; + return this; + } + + /** + * Gets the runtime request id of this call. + *

    + * Experimental. This is the key + * {@code session.tools.handlePendingToolCall} and + * {@code session.tools.listPendingRequests} use. A root-agent call stays + * answerable after the session is resumed with pending work continued; a + * sub-agent's call can be answered only while that sub-agent is still running. + * + * @return the request id, or {@code null} if the call did not arrive as an + * external tool request + * @since 1.0.15-preview.1 + */ + @CopilotExperimental + public String getRequestId() { + return requestId; + } + + /** + * Sets the runtime request id of this call. + *

    + * Note: This method is intended for internal SDK use. Users + * typically do not need to call this method directly. + * + * @param requestId + * the request id + * @return this invocation for method chaining + */ + @CopilotExperimental + public ToolInvocation setRequestId(String requestId) { + this.requestId = requestId; + return this; + } } diff --git a/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java b/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java index 40654292f8..f2735cae7d 100644 --- a/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java +++ b/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java @@ -6,6 +6,9 @@ import static org.junit.jupiter.api.Assertions.*; +import java.util.List; +import java.util.Map; + import org.junit.jupiter.api.Test; import com.github.copilot.rpc.AgentInfo; @@ -22,6 +25,7 @@ void defaultValuesAreNull() { assertNull(agent.getDisplayName()); assertNull(agent.getDescription()); assertNull(agent.getModel()); + assertNull(agent.getHooks()); } @Test @@ -52,6 +56,21 @@ void modelGetterSetter() { assertEquals("alpha/sonnet", agent.getModel()); } + @Test + void hooksGetterSetterAndJsonRoundTrip() throws Exception { + Map>> hooks = Map.of("preToolUse", + List.of(Map.of("type", "command", "bash", "echo scoped-hook", "timeoutSec", 10))); + var agent = new AgentInfo().setName("coder").setHooks(hooks); + assertEquals(hooks, agent.getHooks()); + + var mapper = JsonRpcClient.getObjectMapper(); + var json = mapper.valueToTree(agent); + assertEquals(mapper.valueToTree(hooks), json.get("hooks")); + var restored = mapper.treeToValue(json, AgentInfo.class); + assertEquals(hooks, restored.getHooks()); + assertNull(mapper.readValue("{\"name\":\"plain-agent\"}", AgentInfo.class).getHooks()); + } + @Test void fluentChainingReturnsThis() { var agent = new AgentInfo().setName("coder").setDisplayName("Code Assistant") @@ -70,5 +89,6 @@ void fluentChainingReturnsSameInstance() { assertSame(agent, agent.setDisplayName("Test")); assertSame(agent, agent.setDescription("A test agent")); assertSame(agent, agent.setModel("alpha/sonnet")); + assertSame(agent, agent.setHooks(Map.of())); } } diff --git a/java/sdk/src/test/java/com/github/copilot/AhpHostTest.java b/java/sdk/src/test/java/com/github/copilot/AhpHostTest.java index 2ffaf50442..136248cb0a 100644 --- a/java/sdk/src/test/java/com/github/copilot/AhpHostTest.java +++ b/java/sdk/src/test/java/com/github/copilot/AhpHostTest.java @@ -72,7 +72,7 @@ void forwardsEnvironmentFieldsForRuntimeValidation() throws Exception { @CsvSource({"true,false", "false,true", "true,true"}) void forwardsExplicitTransportsAndOptionalReadiness(boolean local, boolean github) throws Exception { try (var server = new FakeRuntime(); var client = server.client()) { - var options = new AhpHostOptions(); + var options = new AhpHostOptions().setComputeId("compute"); if (local) { options.setLocalServer(new HostLocalServerOptions("127.0.0.1", 0L, "test-token", true)); } @@ -81,6 +81,7 @@ void forwardsExplicitTransportsAndOptionalReadiness(boolean local, boolean githu } try (var host = await(client.startAhpHost(options))) { var request = await(server.startRequest); + assertEquals("compute", request.path("computeId").asText()); assertEquals(local, request.hasNonNull("localServer")); assertEquals(github, request.hasNonNull("githubEnvironment")); for (String oldField : List.of("hostname", "port", "token", "requireConnectionToken")) { @@ -106,29 +107,54 @@ void forwardsExplicitTransportsAndOptionalReadiness(boolean local, boolean githu void snapshotsOptionsBeforeConnecting() throws Exception { try (var server = new FakeRuntime(); var client = server.client()) { server.finishConnect = new CompletableFuture<>(); - var options = localOptions().setGithubEnvironment(new HostGitHubEnvironmentOptions("original", "compute")); + var options = localOptions().setComputeId("compute") + .setGithubEnvironment(new HostGitHubEnvironmentOptions("original", "compute")); var pending = client.startAhpHost(options); await(server.connectEntered); try { - options.setLocalServer(null).setGithubEnvironment(new HostGitHubEnvironmentOptions("", "")); + options.setComputeId("changed").setLocalServer(null) + .setGithubEnvironment(new HostGitHubEnvironmentOptions("", "")); } finally { server.finishConnect.complete(null); } try (var host = await(pending)) { var request = await(server.startRequest); assertTrue(request.hasNonNull("localServer")); + assertEquals("compute", request.path("computeId").asText()); assertEquals("original", request.path("githubEnvironment").path("name").asText()); assertEquals("compute", request.path("githubEnvironment").path("computeId").asText()); } } } + @Test + void legacyEnvironmentOptionsOmitConnectionBinding() throws Exception { + try (var server = new FakeRuntime(); + var client = server.client(); + var host = await(client.startAhpHost(new AhpHostOptions() + .setGithubEnvironment(new HostGitHubEnvironmentOptions("test host", "compute"))))) { + assertFalse(await(server.startRequest).path("githubEnvironment").has("requireConnectionBinding")); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void forwardsExplicitConnectionBinding(boolean required) throws Exception { + try (var server = new FakeRuntime(); + var client = server.client(); + var host = await(client.startAhpHost(new AhpHostOptions() + .setGithubEnvironment(new HostGitHubEnvironmentOptions("test host", "compute", required))))) { + assertEquals(required, + await(server.startRequest).path("githubEnvironment").path("requireConnectionBinding").asBoolean()); + } + } + @Test void publicHostApiExposesOnlyOwnerOperations() { var methods = Arrays.stream(ServerHostApi.class.getMethods()) .filter(method -> method.getDeclaringClass() == ServerHostApi.class).map(method -> method.getName()) .collect(Collectors.toSet()); - assertEquals(Set.of("start", "dispose", "publishSession"), methods); + assertEquals(Set.of("start", "dispose", "publishSession", "listSessions"), methods); } @Test @@ -330,6 +356,8 @@ void publishesDisposesRepeatedlyAndRetainsOriginalTransport() throws Exception { }))); assertNull(host.getPid()); assertEquals("ahp-session:/resident", await(host.publishSession("resident")).sessionUri()); + assertTrue(await(host.listSessions()).sessions().isEmpty()); + assertEquals(host.getHostId(), await(server.listSessionsRequest).path("hostId").asText()); await(CompletableFuture.allOf(host.dispose(), host.dispose())); await(exited); assertEquals(2, server.disposals.get()); @@ -347,6 +375,7 @@ private static final class FakeRuntime implements AutoCloseable { final AtomicInteger disposals = new AtomicInteger(); final CompletableFuture startEntered = new CompletableFuture<>(); final CompletableFuture startRequest = new CompletableFuture<>(); + final CompletableFuture listSessionsRequest = new CompletableFuture<>(); final CompletableFuture disposedHost = new CompletableFuture<>(); final CompletableFuture connectEntered = new CompletableFuture<>(); volatile CompletableFuture finishConnect = CompletableFuture.completedFuture(null); @@ -390,6 +419,10 @@ private static final class FakeRuntime implements AutoCloseable { (id, params) -> respond(transport, id, Map.of("sessionId", params.get("sessionId").asText(), "sessionUri", "ahp-session:/" + params.get("sessionId").asText()))); + transport.registerMethodHandler("host.listSessions", (id, params) -> { + listSessionsRequest.complete(params); + respond(transport, id, Map.of("sessions", List.of())); + }); transport.registerMethodHandler("host.dispose", (id, params) -> { disposals.incrementAndGet(); try { diff --git a/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java b/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java index d93cbf995b..1ce94b4b19 100644 --- a/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java +++ b/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -20,6 +22,7 @@ import com.github.copilot.generated.rpc.SessionEventLogReadParams; import com.github.copilot.rpc.AutoTier; import com.github.copilot.rpc.CapiSessionOptions; +import com.github.copilot.rpc.CopilotClientOptions; import com.github.copilot.rpc.MessageOptions; import com.github.copilot.rpc.PermissionHandler; import com.github.copilot.rpc.ResumeSessionConfig; @@ -200,12 +203,19 @@ void shouldRestoreAndOverrideFastAutoTierOnColdResume() throws Exception { void shouldCommitFastAutoTierAfterSuccessfulTurn() throws Exception { ctx.configureForTest("auto_tier", "should_commit_fast_auto_tier_after_successful_turn"); - try (CopilotClient client = ctx.createClient(); + // Keep this invocation's detach trace outside the home removed by context + // teardown. + Path logDirectory = Files.createTempDirectory(Files.createDirectories(Path.of("target", "failsafe-reports")), + "auto-tier-detach-").toAbsolutePath(); + try (CopilotClient client = ctx.createClient(new CopilotClientOptions().setLogLevel("debug") + .setCliArgs(new String[]{"--log-dir", logDirectory.toString()})); CopilotSession session = client .createSession(new SessionConfig().setModel(MODEL_ID) .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setCapi(new CapiSessionOptions() .setAutoTier(AutoTier.EFFICIENCY).setEnableWebSocketResponses(false))) .get(30, TimeUnit.SECONDS)) { + System.err.println( + "AutoTierIT detach diagnostics: session=" + session.getSessionId() + " logs=" + logDirectory); var modelChangedFuture = new CompletableFuture(); try (var subscription = session.on(SessionModelChangeEvent.class, event -> { if (event.getData().autoTier() == com.github.copilot.generated.AutoTier.FAST) { diff --git a/java/sdk/src/test/java/com/github/copilot/BuiltinPluginDirectoriesTest.java b/java/sdk/src/test/java/com/github/copilot/BuiltinPluginDirectoriesTest.java index b5f89e5f9f..7a42c2c45e 100644 --- a/java/sdk/src/test/java/com/github/copilot/BuiltinPluginDirectoriesTest.java +++ b/java/sdk/src/test/java/com/github/copilot/BuiltinPluginDirectoriesTest.java @@ -90,15 +90,16 @@ JsonNode awaitBuiltinParams() throws Exception { private void acceptLoop() { try { Socket socket = serverSocket.accept(); - JsonRpcClient server = JsonRpcClient.fromSocket(socket); - server.registerMethodHandler("ping", (id, params) -> respond(server, id, - Map.of("message", "pong", "timestamp", "2026-09-21T00:00:00Z", "protocolVersion", 3))); - server.registerMethodHandler("connect", (id, params) -> respond(server, id, - Map.of("ok", true, "protocolVersion", 3, "version", "test"))); - server.registerMethodHandler("plugins.builtin.set", (id, params) -> { - builtinSetCount.incrementAndGet(); - builtinParams.complete(params); - respond(server, id, Map.of()); + JsonRpcClient server = JsonRpcClient.fromSocket(socket, rpc -> { + rpc.registerMethodHandler("ping", (id, params) -> respond(rpc, id, + Map.of("message", "pong", "timestamp", "2026-09-21T00:00:00Z", "protocolVersion", 3))); + rpc.registerMethodHandler("connect", (id, params) -> respond(rpc, id, + Map.of("ok", true, "protocolVersion", 3, "version", "test"))); + rpc.registerMethodHandler("plugins.builtin.set", (id, params) -> { + builtinSetCount.incrementAndGet(); + builtinParams.complete(params); + respond(rpc, id, Map.of()); + }); }); ready.complete(server); } catch (IOException e) { diff --git a/java/sdk/src/test/java/com/github/copilot/CapiSessionOptionsTest.java b/java/sdk/src/test/java/com/github/copilot/CapiSessionOptionsTest.java index aeb4ffe0ad..cc4e2fde3f 100644 --- a/java/sdk/src/test/java/com/github/copilot/CapiSessionOptionsTest.java +++ b/java/sdk/src/test/java/com/github/copilot/CapiSessionOptionsTest.java @@ -14,7 +14,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import java.util.stream.Stream; import com.fasterxml.jackson.databind.JsonNode; @@ -68,7 +70,7 @@ void omitsUnsetEnableWebSocketResponses() { } @ParameterizedTest - @CsvSource({"EFFICIENCY,efficiency", "BALANCE,balance", "INTELLIGENCE,intelligence", "FAST,fast"}) + @MethodSource("canonicalAutoTiers") void autoTierCanonicalValuesRoundTripAndForward(AutoTier tier, String value) throws Exception { var mapper = JsonRpcClient.getObjectMapper(); var capi = new CapiSessionOptions().setAutoTier(tier); @@ -90,13 +92,25 @@ void autoTierCanonicalValuesRoundTripAndForward(AutoTier tier, String value) thr } @Test - void autoTierRejectsNoncanonicalValues() { + void autoTierPreservesServerIdentifiersAndRejectsMalformedValues() throws Exception { + var mapper = JsonRpcClient.getObjectMapper(); for (String value : new String[]{"balanced", "Balance", "unknown"}) { + var tier = AutoTier.fromValue(value); + assertEquals(value, tier.getValue()); + assertEquals(value, mapper.valueToTree(tier).asText()); + assertEquals(tier, mapper.readValue("\"" + value + "\"", AutoTier.class)); + } + for (String value : new String[]{"", "two words", "\n"}) { assertThrows(IllegalArgumentException.class, () -> AutoTier.fromValue(value)); } assertNull(AutoTier.fromValue(null)); } + private static Stream canonicalAutoTiers() { + return Stream.of(Arguments.of(AutoTier.EFFICIENCY, "efficiency"), Arguments.of(AutoTier.BALANCE, "balance"), + Arguments.of(AutoTier.INTELLIGENCE, "intelligence"), Arguments.of(AutoTier.FAST, "fast")); + } + @Test void clearingAutoTierOmitsIt() { var capi = new CapiSessionOptions().setAutoTier(AutoTier.BALANCE).setAutoTier(null); diff --git a/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java b/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java index 462fbc17cd..9dea8d8c2a 100644 --- a/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java +++ b/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java @@ -7,13 +7,22 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.net.ServerSocket; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; +import java.util.List; import java.util.Map; +import java.util.concurrent.CompletionException; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import com.github.copilot.ffi.NativeRuntimeLoader; import com.github.copilot.rpc.CopilotClientMode; @@ -190,9 +199,167 @@ void processInfoWithNullPort() { assertNull(info.port()); } - // ===== resolveCliCommand tests (via startCliServer) ===== - // resolveCliCommand is private, so we test indirectly through startCliServer - // with specific cliPath values. + // ===== resolveCliCommand tests ===== + + @ParameterizedTest + @ValueSource(strings = {"NoDefaultCurrentDirectoryInExePath", "nodefaultcurrentdirectoryinexepath"}) + @EnabledOnOs(OS.WINDOWS) + void bareWindowsCliPathHonorsCurrentDirectorySearchOptOut(String optOutKey) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Files.createFile(tempDir.resolve("copilot.EXE")); + Path executable = Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()).setUseStdio(true) + .setEnvironment(Map.of("Path", bin.toString(), "PATHEXT", ".EXE", optOutKey, "")); + + assertClientAttemptsExecutable(options, executable); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void bareWindowsCliPathSearchesCurrentDirectoryWithoutOptOut() throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Path executable = Files.createFile(tempDir.resolve("copilot.EXE")); + Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()).setUseStdio(true) + .setEnvironment(Map.of("PATH", bin.toString(), "PATHEXT", ".EXE")); + + assertClientAttemptsExecutable(options, executable); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + @EnabledOnOs(OS.WINDOWS) + void explicitWindowsCurrentDirectorySearchIsPreservedWithOptOut(boolean relativeCliPath) throws Exception { + Path executable = Files.createFile(tempDir.resolve(".").resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath(relativeCliPath ? ".\\copilot.EXE" : "copilot") + .setCwd(tempDir.toString()).setUseStdio(true).setEnvironment(Map.of("PATH", relativeCliPath ? "" : ".", + "PATHEXT", ".EXE", "NoDefaultCurrentDirectoryInExePath", "")); + + assertClientAttemptsExecutable(options, executable); + } + + @ParameterizedTest + @ValueSource(strings = {"", "C:\\invalid|entry"}) + @EnabledOnOs(OS.WINDOWS) + void invalidWindowsCommandIsNotPassedToShellWhenCurrentDirectorySearchIsDisabled(String path) { + var options = new CopilotClientOptions().setCliPath("copilot|invalid").setCwd(tempDir.toString()) + .setUseStdio(true) + .setEnvironment(Map.of("PATH", path, "PATHEXT", ".EXE", "NoDefaultCurrentDirectoryInExePath", "")); + + try (var client = new CopilotClient(options)) { + Throwable error = assertThrows(CompletionException.class, () -> client.start().join()); + while (error.getCause() != null) { + error = error.getCause(); + } + var invalidPath = assertInstanceOf(InvalidPathException.class, error); + assertEquals("copilot|invalid.EXE", invalidPath.getInput()); + } + } + + private static void assertClientAttemptsExecutable(CopilotClientOptions options, Path executable) { + // Empty executables expose the attempted OS launch path without running a + // child. + try (var client = new CopilotClient(options)) { + Throwable error = assertThrows(CompletionException.class, () -> client.start().join()); + while (!(error instanceof IOException) && error.getCause() != null) { + error = error.getCause(); + } + var launchError = assertInstanceOf(IOException.class, error); + assertTrue(launchError.getMessage().contains("\"" + executable + "\""), launchError::getMessage); + } + } + + @ParameterizedTest + @ValueSource(strings = {"tools/copilot.exe", "tools\\copilot", ".\\tools\\copilot.EXE"}) + @EnabledOnOs(OS.WINDOWS) + void relativeWindowsCliPathDoesNotSearchPathDirectories(String cliPath) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Path tools = Files.createDirectory(bin.resolve("tools")); + Path unrelated = Files.createFile(tools.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath(cliPath).setCwd(tempDir.toString()).setUseStdio(false) + .setEnvironment(Map.of("PATH", bin.toString(), "PATHEXT", ".EXE")); + + try (var client = new CopilotClient(options)) { + Throwable error = assertThrows(CompletionException.class, () -> client.start().join()); + while (error.getCause() != null) { + error = error.getCause(); + } + var launchError = assertInstanceOf(IOException.class, error); + assertTrue(launchError.getMessage().startsWith("CLI process exited unexpectedly."), + launchError::getMessage); + assertFalse(launchError.getMessage().contains(unrelated.toString()), launchError::getMessage); + } + } + + @ParameterizedTest + @ValueSource(strings = {" C:\\invalid", "C:\\invalid ", "C:\\invalidentry", + "C:\\invalid|entry", "C:\\invalid?entry", "C:\\invalid*entry", "C:\\invalid\"entry"}) + @EnabledOnOs(OS.WINDOWS) + void windowsNativeExecutableSkipsMalformedPathEntries(String malformedEntry) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin with spaces")); + Path executable = Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()) + .setEnvironment(Map.of("Path", malformedEntry + ";\"" + bin + "\"", "PATHEXT", ".CMD;.EXE")); + + assertEquals(List.of(executable.toString(), "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @ParameterizedTest + @ValueSource(strings = {".CMD", ".BAT"}) + @EnabledOnOs(OS.WINDOWS) + void windowsCommandWrapperAfterMalformedPathEntryUsesShell(String extension) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Files.createFile(bin.resolve("copilot" + extension)); + Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCwd(tempDir.toString()) + .setEnvironment(Map.of(NativeRuntimeLoader.COPILOT_CLI_PATH_ENV, "copilot", "PATH", + "C:\\invalid|entry;" + bin, "PATHEXT", extension + ";.EXE")); + + assertEquals(List.of("cmd", "/c", "copilot", "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void windowsCommandFallsBackToShellWhenPathEntriesAreMalformed() throws Exception { + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()) + .setEnvironment(Map.of("PATH", " C:\\invalid;C:\\invalid|entry")); + + assertEquals(List.of("cmd", "/c", "copilot", "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + @EnabledOnOs(OS.WINDOWS) + void explicitWindowsExecutablePathDoesNotDependOnPath(boolean absolute) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Path executable = Files.createFile(bin.resolve("copilot.exe")); + String cliPath = (absolute ? executable : tempDir.relativize(executable)).toString(); + var options = new CopilotClientOptions().setCliPath(cliPath).setCwd(tempDir.toString()) + .setEnvironment(Map.of("PATH", "C:\\invalid|entry")); + + assertEquals(List.of(executable.toString(), "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void malformedWindowsCliPathIsNotSkipped() { + var options = new CopilotClientOptions().setCliPath("copilot|invalid").setCwd(tempDir.toString()) + .setEnvironment(Map.of("PATH", "C:\\invalid|entry", "PATHEXT", ".EXE")); + + var error = assertThrows(InvocationTargetException.class, + () -> resolveCliCommand(new CliServerManager(options))); + var cause = assertInstanceOf(InvalidPathException.class, error.getCause()); + assertEquals("copilot|invalid.EXE", cause.getInput()); + } + + @SuppressWarnings("unchecked") + private static List resolveCliCommand(CliServerManager manager) throws Exception { + var resolve = CliServerManager.class.getDeclaredMethod("resolveCliCommand", String.class, List.class); + resolve.setAccessible(true); + return (List) resolve.invoke(manager, manager.resolveCliLaunch().executable(), List.of("--server")); + } + + // ===== startCliServer tests ===== // On Windows, "/nonexistent/copilot" is not an absolute path (no drive letter), // so resolveCliCommand wraps it with "cmd /c" and ProcessBuilder.start() diff --git a/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java b/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java index 04afa58596..169c39fdcb 100644 --- a/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java +++ b/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java @@ -80,8 +80,8 @@ void testShouldForwardAdvancedSessionCreationOptionsToTheCli() throws Exception try (var client = fake.createClient()) { var session = client.createSession(new SessionConfig().setSessionId("java-create-session") - .setClientName("java-e2e-client").setModel("gpt-5-mini").setReasoningEffort("low") - .setReasoningSummary("none").setContextTier("long_context") + .setName("java named at create").setClientName("java-e2e-client").setModel("gpt-5-mini") + .setReasoningEffort("low").setReasoningSummary("none").setContextTier("long_context") .setAvailableTools(java.util.List.of("bash")).setExcludedTools(java.util.List.of("grep")) .setExcludedBuiltInAgents(java.util.List.of("explore")).setEnableSessionTelemetry(true) .setEnableCitations(true).setSessionLimits(new SessionLimitsConfig(42.0)) @@ -100,6 +100,7 @@ void testShouldForwardAdvancedSessionCreationOptionsToTheCli() throws Exception var create = fake.capturedRequest("session.create").path("params"); assertEquals("java-create-session", create.path("sessionId").asText()); + assertEquals("java named at create", create.path("name").asText()); assertEquals("java-e2e-client", create.path("clientName").asText()); assertEquals("gpt-5-mini", create.path("model").asText()); assertEquals("low", create.path("reasoningEffort").asText()); diff --git a/java/sdk/src/test/java/com/github/copilot/ConfigCloneTest.java b/java/sdk/src/test/java/com/github/copilot/ConfigCloneTest.java index 8f937fcb99..fba9a6413b 100644 --- a/java/sdk/src/test/java/com/github/copilot/ConfigCloneTest.java +++ b/java/sdk/src/test/java/com/github/copilot/ConfigCloneTest.java @@ -323,6 +323,17 @@ void sessionConfigGranularMultitenancyFieldsCopied() { assertFalse(cloned.getEnableSkills().orElse(true)); } + @Test + @AllowCopilotExperimental + void sessionConfigSkillProviderCloned() { + SkillProvider provider = testSkillProvider(); + SessionConfig original = new SessionConfig().setSkillProvider(provider); + + SessionConfig cloned = original.clone(); + + assertSame(provider, cloned.getSkillProvider()); + } + @Test void resumeSessionConfigEnableSessionTelemetryCopied() { ResumeSessionConfig original = new ResumeSessionConfig(); @@ -362,6 +373,17 @@ void resumeSessionConfigGranularMultitenancyFieldsCopied() { assertTrue(cloned.getEnableSkills().orElse(false)); } + @Test + @AllowCopilotExperimental + void resumeSessionConfigSkillProviderCloned() { + SkillProvider provider = testSkillProvider(); + ResumeSessionConfig original = new ResumeSessionConfig().setSkillProvider(provider); + + ResumeSessionConfig cloned = original.clone(); + + assertSame(provider, cloned.getSkillProvider()); + } + @Test void clonePreservesNullFields() { CopilotClientOptions opts = new CopilotClientOptions(); @@ -548,4 +570,19 @@ void resumeSessionConfigCloneCopiesModeSwitchHandlers() { assertSame(original.getOnExitPlanMode(), cloned.getOnExitPlanMode()); assertSame(original.getOnAutoModeSwitch(), cloned.getOnAutoModeSwitch()); } + + @AllowCopilotExperimental + private static SkillProvider testSkillProvider() { + return new SkillProvider() { + @Override + public CompletableFuture> listSkills() { + return CompletableFuture.completedFuture(List.of()); + } + + @Override + public CompletableFuture readSkill(String name) { + return CompletableFuture.completedFuture(null); + } + }; + } } diff --git a/java/sdk/src/test/java/com/github/copilot/CopilotClientTest.java b/java/sdk/src/test/java/com/github/copilot/CopilotClientTest.java index 9055cb19f7..7bc27fe321 100644 --- a/java/sdk/src/test/java/com/github/copilot/CopilotClientTest.java +++ b/java/sdk/src/test/java/com/github/copilot/CopilotClientTest.java @@ -9,11 +9,17 @@ import org.junit.jupiter.api.io.TempDir; import com.github.copilot.generated.ExternalToolRequestedEvent; +import com.github.copilot.rpc.CloudSessionOptions; import com.github.copilot.rpc.CopilotClientOptions; +import com.github.copilot.rpc.CopilotClientMode; +import com.github.copilot.rpc.CreateSessionRequest; +import com.github.copilot.rpc.CreateSessionResponse; import com.github.copilot.rpc.DeleteSessionResponse; import com.github.copilot.rpc.GitHubTokenProviderResult; import com.github.copilot.rpc.PermissionHandler; import com.github.copilot.rpc.PingResponse; +import com.github.copilot.rpc.ResumeSessionConfig; +import com.github.copilot.rpc.ResumeSessionResponse; import com.github.copilot.rpc.SessionConfig; import com.github.copilot.rpc.SessionLifecycleEvent; import com.github.copilot.rpc.SessionLifecycleEventTypes; @@ -22,6 +28,7 @@ import java.io.OutputStream; import java.lang.reflect.Field; import java.io.BufferedReader; +import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; @@ -176,6 +183,137 @@ void testDeleteSessionReleasesGitHubTokenProvider() throws Exception { } } + @Test + @AllowCopilotExperimental + void cloudSessionWithSkillProviderIsRejectedBeforeConnectingOrCallingProvider() throws Exception { + var providerCalls = new AtomicInteger(); + SkillProvider provider = new SkillProvider() { + @Override + public CompletableFuture> listSkills() { + providerCalls.incrementAndGet(); + return CompletableFuture.completedFuture(List.of()); + } + + @Override + public CompletableFuture readSkill(String name) { + providerCalls.incrementAndGet(); + return CompletableFuture.completedFuture(null); + } + }; + + try (var client = new CopilotClient(new CopilotClientOptions().setAutoStart(false))) { + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setCloud(new CloudSessionOptions()).setSkillProvider(provider); + + ExecutionException error = assertThrows(ExecutionException.class, () -> client.createSession(config).get()); + assertInstanceOf(IllegalArgumentException.class, error.getCause()); + assertEquals("Skill providers are not supported for cloud sessions.", error.getCause().getMessage()); + assertEquals(0, providerCalls.get()); + } + } + + @Test + @AllowCopilotExperimental + void emptyModeCreateWithSkillProviderSendsFlagsAndRegistersBeforeRpc() throws Exception { + var client = new CopilotClient(new CopilotClientOptions().setAutoStart(false).setMode(CopilotClientMode.EMPTY) + .setCopilotHome(System.getProperty("java.io.tmpdir"))); + var rpc = mock(JsonRpcClient.class); + setConnectionFuture(client, rpc, null); + SkillProvider provider = testSkillProvider(); + var createRequest = new AtomicReference(); + + when(rpc.invoke(eq("session.create"), any(), eq(CreateSessionResponse.class))).thenAnswer(invocation -> { + CreateSessionRequest request = invocation.getArgument(1); + createRequest.set(request); + assertTrue(request.getHasSkillProvider()); + assertFalse(request.getEnableSkills()); + assertSame(provider, registeredSkillProvider(client, "skill-provider-session")); + return CompletableFuture + .completedFuture(new CreateSessionResponse("skill-provider-session", null, null, null)); + }); + when(rpc.invoke(eq("session.options.update"), any(), eq(Void.class))) + .thenReturn(CompletableFuture.completedFuture(null)); + + try { + var config = new SessionConfig().setSessionId("skill-provider-session") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setAvailableTools(List.of()) + .setSkillProvider(provider); + + CopilotSession session = client.createSession(config).get(); + + assertSame(provider, session.getSkillProvider()); + assertNotNull(createRequest.get()); + assertTrue(createRequest.get().getHasSkillProvider()); + assertFalse(createRequest.get().getEnableSkills()); + } finally { + client.forceStop().get(); + } + } + + @Test + @AllowCopilotExperimental + void emptyModeResumeValidationFailureKeepsResidentSkillProvider() throws Exception { + var client = new CopilotClient(new CopilotClientOptions().setAutoStart(false).setMode(CopilotClientMode.EMPTY) + .setCopilotHome(System.getProperty("java.io.tmpdir"))); + var rpc = mock(JsonRpcClient.class); + setConnectionFuture(client, rpc, null); + SkillProvider resident = testSkillProvider(); + when(rpc.invoke(eq("session.create"), any(), eq(CreateSessionResponse.class))).thenReturn( + CompletableFuture.completedFuture(new CreateSessionResponse("resident-session", null, null, null))); + when(rpc.invoke(eq("session.options.update"), any(), eq(Void.class))) + .thenReturn(CompletableFuture.completedFuture(null)); + + try { + client.createSession(new SessionConfig().setSessionId("resident-session") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setAvailableTools(List.of()) + .setSkillProvider(resident)).get(); + + var resumeConfig = new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setSkillProvider(testSkillProvider()); + var error = assertThrows(ExecutionException.class, + () -> client.resumeSession("resident-session", resumeConfig).get()); + + assertInstanceOf(IllegalArgumentException.class, error.getCause()); + assertSame(resident, registeredSkillProvider(client, "resident-session")); + verify(rpc, never()).invoke(eq("session.resume"), any(), any()); + } finally { + client.forceStop().get(); + } + } + + @Test + @AllowCopilotExperimental + void failedResumeDoesNotEvictAConcurrentResume() throws Exception { + var client = new CopilotClient( + new CopilotClientOptions().setAutoStart(false).setCopilotHome(System.getProperty("java.io.tmpdir"))); + var rpc = mock(JsonRpcClient.class); + setConnectionFuture(client, rpc, null); + when(rpc.invoke(eq("session.create"), any(), eq(CreateSessionResponse.class))).thenReturn( + CompletableFuture.completedFuture(new CreateSessionResponse("shared-session", null, null, null))); + when(rpc.invoke(eq("session.options.update"), any(), eq(Void.class))) + .thenReturn(CompletableFuture.completedFuture(null)); + var firstResume = new CompletableFuture(); + when(rpc.invoke(eq("session.resume"), any(), eq(ResumeSessionResponse.class))).thenReturn(firstResume, + CompletableFuture.completedFuture(new ResumeSessionResponse("shared-session", null, null, null))); + + try { + client.createSession(new SessionConfig().setSessionId("shared-session") + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(testSkillProvider())).get(); + var failing = client.resumeSession("shared-session", new ResumeSessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(testSkillProvider())); + SkillProvider winner = testSkillProvider(); + client.resumeSession("shared-session", new ResumeSessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(winner)).get(); + + firstResume.completeExceptionally(new RuntimeException("resume failed")); + + assertThrows(ExecutionException.class, failing::get); + assertSame(winner, registeredSkillProvider(client, "shared-session")); + } finally { + client.forceStop().get(); + } + } + @Test void testClientConstruction() { var client = new CopilotClient(); @@ -274,26 +412,64 @@ void testStartupWriteFailureDrainsStderrBeforeKillingChild(@TempDir Path tempDir process.exit(1); } }); - fs.closeSync(0); process.stdout.write('started\\n'); """); var options = new CopilotClientOptions().setCliPath(script.toString()).setUseStdio(true); var manager = spy(new CliServerManager(options)); var child = new AtomicReference(); + var failedOutput = new AtomicReference(); + var writeFailure = new IOException("Controlled startup write failure"); + doAnswer(invocation -> { + CliServerManager.ProcessInfo info = (CliServerManager.ProcessInfo) invocation.callRealMethod(); + child.set(info.process()); + // Closing fd 0 does not reliably fail the first parent write on Windows. + var output = new FilterOutputStream(info.process().getOutputStream()) { + @Override + public void write(int value) throws IOException { + throw writeFailure; + } + + @Override + public void write(byte[] bytes, int offset, int length) throws IOException { + throw writeFailure; + } + + @Override + public void close() throws IOException { + // No write succeeds, so there is nothing to flush on this failed transport. + out.close(); + } + }; + failedOutput.set(output); + var transportProcess = mock(Process.class, org.mockito.AdditionalAnswers.delegatesTo(info.process())); + doReturn(output).when(transportProcess).getOutputStream(); + return new CliServerManager.ProcessInfo(transportProcess, info.port()); + }).when(manager).startCliServer(); doAnswer(invocation -> { Process process = invocation.getArgument(0); - child.set(process); var reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); assertEquals("started", reader.readLine()); return invocation.callRealMethod(); }).when(manager).connectToServer(any(Process.class), isNull(), isNull()); doAnswer(invocation -> { // Release stderr only when startup drains it, while the child is still alive. + assertTrue(child.get().isAlive(), "Startup must drain stderr before killing the controlled child."); Files.createFile(tempDir.resolve("release-stderr")); return invocation.callRealMethod(); }).when(manager).awaitStderrReader(); - try (var client = new CopilotClient(options)) { + try (AutoCloseable childCleanup = () -> { + var process = child.get(); + if (process != null && process.isAlive()) { + process.destroyForcibly(); + assertTrue(process.waitFor(10, TimeUnit.SECONDS), "Could not reap the controlled child."); + } + }; var client = new CopilotClient(options); AutoCloseable outputCleanup = () -> { + var output = failedOutput.get(); + if (output != null) { + output.close(); + } + }) { Field managerField = CopilotClient.class.getDeclaredField("serverManager"); managerField.setAccessible(true); managerField.set(client, manager); @@ -307,14 +483,9 @@ void testStartupWriteFailureDrainsStderrBeforeKillingChild(@TempDir Path tempDir while (original.getCause() != null) { original = original.getCause(); } - assertInstanceOf(IOException.class, original); + assertSame(writeFailure, original, "Startup must preserve the actual failed transport write."); assertNotSame(cause, original, "The startup error must retain its original transport failure."); assertFalse(child.get().isAlive(), "Failed startup retained its child process."); - } finally { - if (child.get() != null && child.get().isAlive()) { - child.get().destroyForcibly(); - assertTrue(child.get().waitFor(10, TimeUnit.SECONDS), "Could not reap the controlled child."); - } } } @@ -579,6 +750,38 @@ void testOnLifecycleMultipleHandlers() throws Exception { // ===== getState() coverage ===== + @Test + void testGetStateDoesNotReportConnectedWhenStartFailsDuringStateRead() throws Exception { + var failure = new IOException("Startup failed"); + // Complete after the first status observation, whichever status getState reads + // first. + var future = new CompletableFuture() { + @Override + public boolean isDone() { + boolean done = super.isDone(); + completeExceptionally(failure); + return done; + } + + @Override + public boolean isCompletedExceptionally() { + boolean failed = super.isCompletedExceptionally(); + completeExceptionally(failure); + return failed; + } + }; + + try (var client = new CopilotClient(new CopilotClientOptions().setAutoStart(false))) { + setConnectionFuture(client, future); + + ConnectionState state = client.getState(); + assertTrue(state == ConnectionState.CONNECTING || state == ConnectionState.ERROR, + "Failed startup must not report CONNECTED, was: " + state); + assertTrue(future.isCompletedExceptionally()); + assertEquals(ConnectionState.ERROR, client.getState()); + } + } + @Test void testGetStateErrorAfterFailedStart() throws Exception { // Use a non-existent CLI path to trigger a startup failure @@ -793,8 +996,37 @@ private static void setConnectionFuture(CopilotClient client, JsonRpcClient rpc, constructor.setAccessible(true); var connection = constructor.newInstance(rpc, process, null, null); + setConnectionFuture(client, CompletableFuture.completedFuture(connection)); + } + + private static void setConnectionFuture(CopilotClient client, CompletableFuture future) throws Exception { Field field = CopilotClient.class.getDeclaredField("connectionFuture"); field.setAccessible(true); - field.set(client, CompletableFuture.completedFuture(connection)); + field.set(client, future); + } + + @AllowCopilotExperimental + private static SkillProvider testSkillProvider() { + return new SkillProvider() { + @Override + public CompletableFuture> listSkills() { + return CompletableFuture.completedFuture(List.of()); + } + + @Override + public CompletableFuture readSkill(String name) { + return CompletableFuture.completedFuture(null); + } + }; + } + + @AllowCopilotExperimental + @SuppressWarnings("unchecked") + private static SkillProvider registeredSkillProvider(CopilotClient client, String sessionId) throws Exception { + Field sessionsField = CopilotClient.class.getDeclaredField("sessions"); + sessionsField.setAccessible(true); + Map sessions = (Map) sessionsField.get(client); + CopilotSession session = sessions.get(sessionId); + return session != null ? session.getSkillProvider() : null; } } diff --git a/java/sdk/src/test/java/com/github/copilot/CopilotSessionTest.java b/java/sdk/src/test/java/com/github/copilot/CopilotSessionTest.java index 94ccda7243..4b876f4bee 100644 --- a/java/sdk/src/test/java/com/github/copilot/CopilotSessionTest.java +++ b/java/sdk/src/test/java/com/github/copilot/CopilotSessionTest.java @@ -17,7 +17,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -178,53 +177,6 @@ void testShouldReceiveSessionEvents() throws Exception { } } - /** - * Verifies that send() returns immediately while events stream in background. - * - * @see Snapshot: - * session/send_returns_immediately_while_events_stream_in_background - */ - @Test - void testSendReturnsImmediatelyWhileEventsStreamInBackground() throws Exception { - ctx.configureForTest("session", "send_returns_immediately_while_events_stream_in_background"); - - try (CopilotClient client = ctx.createClient()) { - CopilotSession session = client - .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); - - var events = new ArrayList(); - var lastMessage = new AtomicReference(); - var done = new CompletableFuture(); - - session.on(evt -> { - events.add(evt.getType()); - if (evt instanceof AssistantMessageEvent msg) { - lastMessage.set(msg); - } else if (evt instanceof SessionIdleEvent) { - done.complete(null); - } - }); - - // Use a slow command so we can verify send() returns before completion - // Use String convenience overload (covers send(String) path) - session.send("Run 'sleep 2 && echo done'").get(); - - // At this point, we might not have received session.idle yet - // The event handling happens asynchronously - - // Wait for completion - done.get(60, TimeUnit.SECONDS); - - assertTrue(events.contains("session.idle")); - assertTrue(events.contains("assistant.message")); - assertNotNull(lastMessage.get()); - assertTrue(lastMessage.get().getData().content().contains("done"), - "Response should contain done: " + lastMessage.get().getData().content()); - - session.close(); - } - } - /** * Verifies that sendAndWait blocks until session is idle and returns the final * assistant message. diff --git a/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java b/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java index 8a0e335758..fa96957d26 100644 --- a/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java +++ b/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java @@ -121,7 +121,7 @@ public static E2ETestContext create() throws IOException, InterruptedException { defaultUser.put("login", "e2e-test-user"); defaultUser.put("id", 12345); defaultUser.put("copilot_plan", "individual_pro"); - defaultUser.put("endpoints", Map.of("api", proxyUrl, "telemetry", "https://localhost:1/telemetry")); + defaultUser.put("endpoints", Map.of("api", proxyUrl, "telemetry", proxyUrl)); defaultUser.put("analytics_tracking_id", "e2e-test-tracking-id"); proxy.setCopilotUserByToken(DEFAULT_GITHUB_TOKEN, defaultUser); diff --git a/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java b/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java index bf307f6547..6e99145ac4 100644 --- a/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java +++ b/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java @@ -6,12 +6,37 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.List; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.databind.ObjectMapper; + class E2ETestContextTest { + @Test + void defaultTelemetryEndpointUsesTheOwnedProxy() throws Exception { + try (E2ETestContext ctx = E2ETestContext.create()) { + var client = HttpClient.newHttpClient(); + var userRequest = HttpRequest.newBuilder(URI.create(ctx.getProxyUrl() + "/copilot_internal/user")) + .header("Authorization", "Bearer " + ctx.getEnvironment().get("GH_TOKEN")).build(); + var userResponse = client.send(userRequest, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, userResponse.statusCode()); + var telemetryEndpoint = new ObjectMapper().readTree(userResponse.body()).path("endpoints").path("telemetry") + .asText(); + assertEquals(ctx.getProxyUrl(), telemetryEndpoint); + var telemetryRequest = HttpRequest.newBuilder(URI.create(telemetryEndpoint + "/telemetry")) + .POST(HttpRequest.BodyPublishers.ofString("{}\n")).build(); + var telemetryResponse = client.send(telemetryRequest, HttpResponse.BodyHandlers.ofString()); + assertEquals(204, telemetryResponse.statusCode()); + assertEquals("", telemetryResponse.body()); + } + } + @Test void expectedUserPromptsParseFoldedBlockScalars() { String snapshot = """ diff --git a/java/sdk/src/test/java/com/github/copilot/EventFidelityTest.java b/java/sdk/src/test/java/com/github/copilot/EventFidelityTest.java index cca63b4d67..ed63d60764 100644 --- a/java/sdk/src/test/java/com/github/copilot/EventFidelityTest.java +++ b/java/sdk/src/test/java/com/github/copilot/EventFidelityTest.java @@ -6,8 +6,8 @@ import static org.junit.jupiter.api.Assertions.*; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.AfterAll; @@ -60,7 +60,7 @@ void testShouldEmitAssistantUsageEventAfterModelCall() throws Exception { CopilotSession session = client .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); - List events = new ArrayList<>(); + List events = new CopyOnWriteArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt("What is 5+5? Reply with just the number.")).get(60, @@ -94,7 +94,7 @@ void testShouldEmitSessionUsageInfoEventAfterModelCall() throws Exception { CopilotSession session = client .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); - List events = new ArrayList<>(); + List events = new CopyOnWriteArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt("What is 5+5? Reply with just the number.")).get(60, diff --git a/java/sdk/src/test/java/com/github/copilot/ForceStopSessionTest.java b/java/sdk/src/test/java/com/github/copilot/ForceStopSessionTest.java new file mode 100644 index 0000000000..1b51dce326 --- /dev/null +++ b/java/sdk/src/test/java/com/github/copilot/ForceStopSessionTest.java @@ -0,0 +1,482 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.copilot.generated.SessionEvent; +import com.github.copilot.generated.SessionIdleEvent; +import com.github.copilot.rpc.CopilotClientOptions; +import com.github.copilot.rpc.MessageOptions; +import com.github.copilot.rpc.PermissionHandler; +import com.github.copilot.rpc.SessionConfig; +import com.github.copilot.rpc.SessionHooks; + +class ForceStopSessionTest { + + @CopilotResponse + public record Answer(int value) { + } + + @Test + void gracefulClosePreservesEventsAndSessionEndHooksUntilDetachCompletes() throws Exception { + var events = new AtomicInteger(); + var hooks = new AtomicInteger(); + try (var server = new Server(); var client = server.createClient()) { + server.emitDetachCallbacks = true; + var session = client.createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setHooks(new SessionHooks().setOnSessionEnd((input, invocation) -> { + assertEquals("user_exit", input.reason()); + hooks.incrementAndGet(); + return CompletableFuture.completedFuture(null); + }))).get(5, TimeUnit.SECONDS); + try (var subscription = session.on(event -> events.incrementAndGet())) { + session.close(); + assertEquals(1, server.detaches.get()); + assertEquals(1, hooks.get(), "Ordinary detach must still invoke the session-end hook"); + assertEquals(1, events.get(), "Ordinary detach must deliver events before callback retirement"); + server.emitIdle(session.getSessionId()); + client.ping("retired detach callbacks barrier").get(5, TimeUnit.SECONDS); + assertEquals(1, events.get(), "Detach completion must retire subsequent callbacks"); + assertThrows(IllegalStateException.class, () -> session.on(event -> fail("Retired handler"))); + session.close(); + assertEquals(1, server.detaches.get(), "Repeated close must not detach again"); + } + } + } + + @Test + void forceStopTerminatesRetainedSessionsWithoutDetachRpc() throws Exception { + try (var server = new Server(); var client = server.createClient()) { + var session = createSession(client); + client.forceStop().get(5, TimeUnit.SECONDS); + + assertThrows(IllegalStateException.class, () -> session.on(event -> fail("Retired handler"))); + assertThrows(IllegalStateException.class, + () -> session.on(SessionIdleEvent.class, event -> fail("Retired typed handler"))); + assertThrows(IllegalStateException.class, () -> session.send("after force stop")); + session.close(); + assertEquals(0, server.detaches.get(), "Local retirement must not detach over RPC"); + } + } + + @Test + void forceStopDropsRemainingSnapshotHandlersWithoutJoiningAnAdmittedHandler() throws Exception { + var entered = new CountDownLatch(1); + var release = new CountDownLatch(1); + var dispatchThread = new AtomicReference(); + var laterCalls = new AtomicInteger(); + try (var server = new Server(); var client = server.createClient()) { + var session = createSession(client); + try (var first = session.on(event -> { + dispatchThread.set(Thread.currentThread()); + entered.countDown(); + awaitRelease(release); + }); var second = session.on(event -> laterCalls.incrementAndGet())) { + try { + server.emitIdle(session.getSessionId()); + assertTrue(entered.await(5, TimeUnit.SECONDS), "The first handler must be admitted"); + client.forceStop().get(5, TimeUnit.SECONDS); + assertEquals(1, release.getCount(), "Force stop must not require releasing the user handler"); + } finally { + release.countDown(); + Thread thread = dispatchThread.get(); + if (thread != null) { + thread.join(5000); + assertFalse(thread.isAlive(), "The stopped event reader must finish after its handler"); + } + } + assertEquals(0, laterCalls.get(), "Retirement must discard the retained dispatch snapshot"); + } + } + } + + @Test + void forceStopRetiresErrorCallbacksWhileGracefulCloseAwaitsDetach() throws Exception { + var entered = new CountDownLatch(1); + var release = new CountDownLatch(1); + var dispatchThread = new AtomicReference(); + var errorCalls = new AtomicInteger(); + try (var server = new Server(); var client = server.createClient()) { + server.holdDetachResponse = true; + var session = createSession(client); + session.setEventErrorHandler((event, error) -> errorCalls.incrementAndGet()); + try (var first = session.on(event -> { + dispatchThread.set(Thread.currentThread()); + entered.countDown(); + awaitRelease(release); + throw new IllegalStateException("Admitted handler failed after forced retirement"); + })) { + try { + server.emitIdle(session.getSessionId()); + assertTrue(entered.await(5, TimeUnit.SECONDS), "The first snapshot handler must be admitted"); + var closing = CompletableFuture.runAsync(session::close); + assertTrue(server.detachEntered.await(5, TimeUnit.SECONDS), "Graceful close must await detach"); + // Prevent graceful close's final retirement from masking force escalation. + synchronized (session) { + client.forceStop().get(5, TimeUnit.SECONDS); + assertFalse(closing.isDone(), "Graceful close must still await its final retirement"); + release.countDown(); + Thread thread = dispatchThread.get(); + thread.join(5000); + assertFalse(thread.isAlive(), "The stopped reader must finish its admitted handler"); + assertEquals(0, errorCalls.get(), "Force stop must discard the unadmitted error callback"); + } + var detachError = assertThrows(ExecutionException.class, () -> closing.get(5, TimeUnit.SECONDS)); + assertInstanceOf(IllegalStateException.class, detachError.getCause()); + } finally { + release.countDown(); + Thread thread = dispatchThread.get(); + if (thread != null) { + thread.join(5000); + assertFalse(thread.isAlive(), "The event reader must finish after forced cleanup"); + } + } + } + } + } + + @ParameterizedTest + @CsvSource({"false, false", "false, true", "true, false", "true, true"}) + void retirementPreservesTerminalOutcomeWhileSchedulerHandoffIsBlocked(boolean terminalError, boolean force) + throws Exception { + var entered = new CountDownLatch(1); + var release = new CountDownLatch(1); + try (var server = new Server(); var client = server.createClient()) { + var session = createSession(client); + var occupying = session.sendAndWait(new MessageOptions().setPrompt("occupy scheduler"), 0); + var continuation = occupying.whenComplete((value, error) -> { + entered.countDown(); + awaitRelease(release); + }); + try (var gate = (AutoCloseable) release::countDown) { + client.ping("first send acknowledgment").get(5, TimeUnit.SECONDS); + server.emitIdle(session.getSessionId()); + assertTrue(entered.await(5, TimeUnit.SECONDS), "A continuation must occupy the session scheduler"); + + var completed = session.sendAndWait(new MessageOptions().setPrompt("completed terminal"), 0); + client.ping("second send acknowledgment").get(5, TimeUnit.SECONDS); + if (terminalError) { + server.emitEvent(session.getSessionId(), "session.error", + Map.of("errorType", "query", "message", "original terminal failure")); + } else { + server.emitEvent(session.getSessionId(), "assistant.message", + Map.of("messageId", "terminal-message", "content", "completed before retirement")); + server.emitIdle(session.getSessionId()); + } + client.ping("terminal dispatch acknowledgment").get(5, TimeUnit.SECONDS); + assertFalse(completed.isDone(), "The received terminal outcome must still await scheduler handoff"); + + if (force) { + client.forceStop().get(5, TimeUnit.SECONDS); + } else { + CompletableFuture.runAsync(session::close).get(5, TimeUnit.SECONDS); + } + if (terminalError) { + var error = assertThrows(ExecutionException.class, () -> completed.get(5, TimeUnit.SECONDS)); + assertEquals("Session error: original terminal failure", error.getCause().getMessage()); + } else { + assertEquals("completed before retirement", completed.get(5, TimeUnit.SECONDS).getData().content()); + } + assertEquals(1, release.getCount(), "Retirement must not join the admitted continuation"); + } + continuation.get(5, TimeUnit.SECONDS); + } + } + + @Test + void forceStopFailsAcknowledgedPlainAndStructuredWaitsWithNoTimeout() throws Exception { + var entered = new CountDownLatch(2); + var release = new CountDownLatch(1); + try (var server = new Server(); var client = server.createClient()) { + var session = createSession(client); + var plain = session.sendAndWait(new MessageOptions().setPrompt("plain"), 0); + var structured = session.sendAndWait(new MessageOptions().setPrompt("structured"), Answer.class, 0); + client.ping("send acknowledgment barrier").get(5, TimeUnit.SECONDS); + assertFalse(plain.isDone()); + assertFalse(structured.isDone()); + + var plainContinuation = plain.whenComplete((value, error) -> { + entered.countDown(); + awaitRelease(release); + }); + var structuredContinuation = structured.whenComplete((value, error) -> { + entered.countDown(); + awaitRelease(release); + }); + try (var gate = (AutoCloseable) release::countDown) { + client.forceStop().get(5, TimeUnit.SECONDS); + assertTrue(entered.await(5, TimeUnit.SECONDS), + "Both waits must retire even while their application continuations are blocked"); + var plainError = assertThrows(ExecutionException.class, () -> plain.get(5, TimeUnit.SECONDS)); + var structuredError = assertThrows(ExecutionException.class, () -> structured.get(5, TimeUnit.SECONDS)); + assertInstanceOf(IllegalStateException.class, plainError.getCause()); + assertInstanceOf(IllegalStateException.class, structuredError.getCause()); + assertTrue(plainError.getCause().getMessage().contains("closed")); + assertTrue(structuredError.getCause().getMessage().contains("closed")); + } + assertThrows(ExecutionException.class, () -> plainContinuation.get(5, TimeUnit.SECONDS)); + assertThrows(ExecutionException.class, () -> structuredContinuation.get(5, TimeUnit.SECONDS)); + } + } + + @Test + void gracefulCloseFailsAcknowledgedWaitsWithoutJoiningTheirContinuations() throws Exception { + var entered = new CountDownLatch(2); + var release = new CountDownLatch(1); + try (var server = new Server(); var client = server.createClient()) { + var session = createSession(client); + var plain = session.sendAndWait(new MessageOptions().setPrompt("plain"), 0); + var structured = session.sendAndWait(new MessageOptions().setPrompt("structured"), Answer.class, 0); + client.ping("send acknowledgment barrier").get(5, TimeUnit.SECONDS); + assertFalse(plain.isDone()); + assertFalse(structured.isDone()); + + var plainContinuation = plain.whenComplete((value, error) -> { + entered.countDown(); + awaitRelease(release); + }); + var structuredContinuation = structured.whenComplete((value, error) -> { + entered.countDown(); + awaitRelease(release); + }); + try (var gate = (AutoCloseable) release::countDown) { + CompletableFuture.runAsync(session::close).get(5, TimeUnit.SECONDS); + assertTrue(entered.await(5, TimeUnit.SECONDS), "Retirement must admit both blocked continuations"); + var plainError = assertThrows(ExecutionException.class, () -> plain.get(5, TimeUnit.SECONDS)); + var structuredError = assertThrows(ExecutionException.class, () -> structured.get(5, TimeUnit.SECONDS)); + assertInstanceOf(IllegalStateException.class, plainError.getCause()); + assertInstanceOf(IllegalStateException.class, structuredError.getCause()); + assertEquals("Session closed before response completed", plainError.getCause().getMessage()); + assertEquals("Session closed before response completed", structuredError.getCause().getMessage()); + assertEquals(1, server.detaches.get(), "Graceful close must still acknowledge one detach"); + session.close(); + assertEquals(1, server.detaches.get(), "Repeated close must not detach again"); + } + assertThrows(ExecutionException.class, () -> plainContinuation.get(5, TimeUnit.SECONDS)); + assertThrows(ExecutionException.class, () -> structuredContinuation.get(5, TimeUnit.SECONDS)); + } + } + + @Test + void duplicateUntypedSubscriptionsStillDispatchOnceAndShareUnsubscription() throws Exception { + var calls = new AtomicInteger(); + try (var server = new Server(); var client = server.createClient()) { + var session = createSession(client); + Consumer handler = event -> calls.incrementAndGet(); + try (var first = session.on(handler); var second = session.on(handler)) { + server.emitIdle(session.getSessionId()); + client.ping("first dispatch barrier").get(5, TimeUnit.SECONDS); + assertEquals(1, calls.get()); + + first.close(); + server.emitIdle(session.getSessionId()); + client.ping("unsubscription barrier").get(5, TimeUnit.SECONDS); + assertEquals(1, calls.get()); + client.forceStop().get(5, TimeUnit.SECONDS); + } + } + } + + private static CopilotSession createSession(CopilotClient client) throws Exception { + return client.createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(5, + TimeUnit.SECONDS); + } + + private static void awaitRelease(CountDownLatch release) { + boolean interrupted = false; + try { + while (true) { + try { + release.await(); + return; + } catch (InterruptedException error) { + interrupted = true; + } + } + } finally { + if (interrupted) { + Thread.currentThread().interrupt(); + } + } + } + + private static final class Server implements AutoCloseable { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + private final ServerSocket listener; + private final Thread thread; + private final AtomicInteger detaches = new AtomicInteger(); + private final CountDownLatch detachEntered = new CountDownLatch(1); + private volatile Socket socket; + private volatile boolean closed; + private volatile boolean emitDetachCallbacks; + private volatile boolean holdDetachResponse; + private volatile Exception failure; + + Server() throws IOException { + listener = new ServerSocket(0, 1, InetAddress.getByName("127.0.0.1")); + thread = new Thread(this::serve, "force-stop-session-server"); + thread.setDaemon(true); + thread.start(); + } + + CopilotClient createClient() { + return new CopilotClient(new CopilotClientOptions().setCliUrl("127.0.0.1:" + listener.getLocalPort())); + } + + void emitIdle(String sessionId) throws IOException { + emitEvent(sessionId, "session.idle", Map.of()); + } + + void emitEvent(String sessionId, String type, Map data) throws IOException { + assertNotNull(socket, "Session creation must establish the connection before events"); + writeMessage(Map.of("jsonrpc", "2.0", "method", "session.event", "params", + Map.of("sessionId", sessionId, "event", + Map.of("type", type, "id", "00000000-0000-0000-0000-000000000001", "timestamp", + "2026-10-05T00:00:00Z", "data", data)))); + } + + private void serve() { + try (Socket accepted = listener.accept()) { + socket = accepted; + JsonNode pendingDetachId = null; + while (!closed) { + JsonNode request = readMessage(accepted.getInputStream()); + if (request == null) { + return; + } + JsonNode params = request.path("params"); + if (holdDetachResponse && request.path("method").asText().equals("session.detach")) { + detaches.incrementAndGet(); + detachEntered.countDown(); + continue; + } + if (!request.has("method") && request.path("id").asLong() == 9_000_000L) { + if (pendingDetachId == null || request.has("error")) { + throw new IOException("Unexpected detach hook response: " + request); + } + var response = MAPPER.createObjectNode().put("jsonrpc", "2.0"); + response.set("id", pendingDetachId); + response.set("result", MAPPER.valueToTree(Map.of("success", true))); + pendingDetachId = null; + writeMessage(response); + continue; + } + if (emitDetachCallbacks && request.path("method").asText().equals("session.detach")) { + detaches.incrementAndGet(); + pendingDetachId = request.get("id"); + String sessionId = params.path("sessionId").asText(); + emitIdle(sessionId); + var hookInput = Map.of("sessionId", sessionId, "timestamp", 0, "cwd", ".", "reason", + "user_exit"); + writeMessage(Map.of("jsonrpc", "2.0", "id", 9_000_000L, "method", "hooks.invoke", "params", + Map.of("sessionId", sessionId, "hookType", "sessionEnd", "input", hookInput))); + continue; + } + Object result = switch (request.path("method").asText()) { + case "connect" -> Map.of("protocolVersion", SdkProtocolVersion.get()); + case "session.create" -> Map.of("sessionId", params.path("sessionId").asText()); + case "session.send" -> Map.of("messageId", params.path("prompt").asText()); + case "session.detach" -> { + detaches.incrementAndGet(); + yield Map.of("success", true); + } + case "ping" -> Map.of("message", params.path("message").asText(), "protocolVersion", + SdkProtocolVersion.get()); + default -> throw new IOException("Unexpected RPC: " + request.path("method")); + }; + var response = MAPPER.createObjectNode().put("jsonrpc", "2.0"); + response.set("id", request.get("id")); + response.set("result", MAPPER.valueToTree(result)); + writeMessage(response); + } + } catch (Exception error) { + if (!closed) { + failure = error; + } + } + } + + private static JsonNode readMessage(InputStream input) throws IOException { + var header = new StringBuilder(); + while (!header.toString().endsWith("\r\n\r\n")) { + int value = input.read(); + if (value < 0) { + if (header.isEmpty()) { + return null; + } + throw new IOException("Truncated RPC header"); + } + header.append((char) value); + if (header.length() > 8192) { + throw new IOException("Oversized RPC header"); + } + } + int length; + try { + length = Integer.parseInt(header.substring(header.indexOf(":") + 1).trim()); + } catch (NumberFormatException error) { + throw new IOException("Invalid Content-Length", error); + } + if (length < 0 || length > 1_048_576) { + throw new IOException("Invalid Content-Length: " + length); + } + byte[] body = input.readNBytes(length); + if (body.length != length) { + throw new IOException("Truncated RPC body"); + } + return MAPPER.readTree(body); + } + + private synchronized void writeMessage(Object message) throws IOException { + byte[] body = MAPPER.writeValueAsBytes(message); + var output = socket.getOutputStream(); + output.write(("Content-Length: " + body.length + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + output.write(body); + output.flush(); + } + + @Override + public void close() throws Exception { + closed = true; + listener.close(); + if (socket != null) { + socket.close(); + } + thread.join(5000); + assertFalse(thread.isAlive(), "The RPC fixture must stop"); + assertNull(failure, "RPC fixture failure: " + failure); + } + } +} diff --git a/java/sdk/src/test/java/com/github/copilot/ImageGenerationConfigTest.java b/java/sdk/src/test/java/com/github/copilot/ImageGenerationConfigTest.java new file mode 100644 index 0000000000..5acace1e7a --- /dev/null +++ b/java/sdk/src/test/java/com/github/copilot/ImageGenerationConfigTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +package com.github.copilot; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.copilot.rpc.ImageGenerationConfig; +import com.github.copilot.rpc.ResumeSessionConfig; +import com.github.copilot.rpc.SessionConfig; + +class ImageGenerationConfigTest { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void createAndResumeForwardExplicitOptIn(boolean enabled) { + var imageGeneration = new ImageGenerationConfig().setEnabled(enabled); + var createConfig = new SessionConfig().setImageGeneration(imageGeneration).clone(); + var resumeConfig = new ResumeSessionConfig().setImageGeneration(imageGeneration).clone(); + assertSame(imageGeneration, createConfig.getImageGeneration()); + assertSame(imageGeneration, resumeConfig.getImageGeneration()); + var create = SessionRequestBuilder.buildCreateRequest(createConfig, "image-test"); + var resume = SessionRequestBuilder.buildResumeRequest("image-test", resumeConfig); + for (Object request : new Object[]{create, resume}) { + JsonNode json = JsonRpcClient.getObjectMapper().valueToTree(request); + assertEquals(enabled, json.get("imageGeneration").get("enabled").booleanValue()); + assertEquals(1, json.get("imageGeneration").size()); + } + } + + @Test + void createAndResumeOmitUnsetOptIn() { + var create = SessionRequestBuilder.buildCreateRequest(new SessionConfig(), "image-test"); + var resume = SessionRequestBuilder.buildResumeRequest("image-test", new ResumeSessionConfig()); + for (Object request : new Object[]{create, resume}) { + JsonNode json = JsonRpcClient.getObjectMapper().valueToTree(request); + assertFalse(json.has("imageGeneration")); + } + JsonNode empty = JsonRpcClient.getObjectMapper().valueToTree(new ImageGenerationConfig()); + assertEquals(0, empty.size()); + } +} diff --git a/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java b/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java index 8db208b53f..f296aba2e5 100644 --- a/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java +++ b/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java @@ -24,6 +24,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.copilot.generated.rpc.ServerRpc; +import com.github.copilot.generated.rpc.SandboxProxyCaCheckRelevanceParams; class JsonRpcClientTest { @@ -104,6 +106,26 @@ private String readRpcMessage(InputStream in) throws IOException { // ---- notify() ---- + @Test + void testGeneratedProxyCaQueriesPreserveBooleanResponses() throws Exception { + try (var pair = createSocketPair()) { + var server = new ServerRpc(pair.client::invoke); + for (boolean expected : new boolean[]{true, false}) { + for (String method : new String[]{"sandbox.proxyCa.checkInstallationSupport", + "sandbox.proxyCa.checkRelevance"}) { + CompletableFuture result = method.endsWith("checkInstallationSupport") + ? server.sandbox.proxyCa.checkInstallationSupport() + : server.sandbox.proxyCa.checkRelevance(new SandboxProxyCaCheckRelevanceParams(null)); + JsonNode request = MAPPER.readTree(readRpcMessage(pair.serverSide.getInputStream())); + assertEquals(method, request.get("method").asText()); + writeRpcMessage(pair.serverSide.getOutputStream(), + "{\"jsonrpc\":\"2.0\",\"id\":" + request.get("id") + ",\"result\":" + expected + "}"); + assertEquals(expected, result.get(5, TimeUnit.SECONDS)); + } + } + } + } + @Test void testNotify() throws Exception { try (var pair = createSocketPair()) { diff --git a/java/sdk/src/test/java/com/github/copilot/ManagedSettingsTest.java b/java/sdk/src/test/java/com/github/copilot/ManagedSettingsTest.java index d6341b26c5..7b1910753f 100644 --- a/java/sdk/src/test/java/com/github/copilot/ManagedSettingsTest.java +++ b/java/sdk/src/test/java/com/github/copilot/ManagedSettingsTest.java @@ -23,22 +23,29 @@ class ManagedSettingsTest { @Test void forwardsManagedSettingsOnCreateAndResume() throws Exception { var permissions = new ManagedSettingsPermissions() - .setDisableBypassPermissionsMode(DisableBypassPermissionsModes.DISABLE).setDeny(List.of("Shell(rm *)")) - .setAsk(List.of("Domain(publish.example)")).setAllow(List.of("Read(**)")); + .setDisableBypassPermissionsMode(DisableBypassPermissionsModes.DISABLE) + .setDisableAssistedPermissionsMode(true).setDeny(List.of("Shell(rm *)")) + .setAsk(List.of("Domain(publish.example)")).setAllow(List.of("Read(**)")) + .setLimitTo(List.of("Domain(github.com)")); var managedSettings = new ManagedSettings().setPermissions(permissions); - var create = SessionRequestBuilder.buildCreateRequest( - new SessionConfig().setEnableManagedSettings(true).setManagedSettings(managedSettings), - "managed-create"); + var create = SessionRequestBuilder.buildCreateRequest(new SessionConfig().setEnableManagedSettings(true) + .setEnforceManagedModelDefaults(true).setManagedSettings(managedSettings), "managed-create"); var resume = SessionRequestBuilder.buildResumeRequest("managed-resume", - new ResumeSessionConfig().setEnableManagedSettings(true).setManagedSettings(managedSettings)); + new ResumeSessionConfig().setEnableManagedSettings(true).setEnforceManagedModelDefaults(true) + .setManagedSettings(managedSettings)); assertEquals(managedSettings, create.getManagedSettings()); assertEquals(managedSettings, resume.getManagedSettings()); + assertTrue(create.getEnforceManagedModelDefaults()); + assertTrue(resume.getEnforceManagedModelDefaults()); var json = new ObjectMapper().writeValueAsString(create); assertTrue(json.contains("\"enableManagedSettings\":true")); + assertTrue(json.contains("\"enforceManagedModelDefaults\":true")); assertTrue(json.contains("\"managedSettings\":{\"permissions\"")); assertTrue(json.contains("\"disableBypassPermissionsMode\":\"disable\"")); + assertTrue(json.contains("\"limitTo\":[\"Domain(github.com)\"]")); + assertTrue(json.contains("\"disableAssistedPermissionsMode\":true")); } @Test @@ -55,7 +62,8 @@ void preservesExplicitEmptyPermissionArrays() throws Exception { // absent (null) list imposes no such restriction. Jackson NON_NULL must // emit an explicit empty array as `[]` and omit null fields, so the two // remain distinguishable on the wire. - var permissions = new ManagedSettingsPermissions().setDeny(List.of()).setAsk(List.of()).setAllow(List.of()); + var permissions = new ManagedSettingsPermissions().setDeny(List.of()).setAsk(List.of()).setAllow(List.of()) + .setLimitTo(List.of()); var managedSettings = new ManagedSettings().setPermissions(permissions); var create = SessionRequestBuilder.buildCreateRequest(new SessionConfig().setManagedSettings(managedSettings), "managed-empty"); @@ -64,6 +72,7 @@ void preservesExplicitEmptyPermissionArrays() throws Exception { assertTrue(json.contains("\"deny\":[]"), json); assertTrue(json.contains("\"ask\":[]"), json); assertTrue(json.contains("\"allow\":[]"), json); + assertTrue(json.contains("\"limitTo\":[]"), json); } @Test diff --git a/java/sdk/src/test/java/com/github/copilot/PackagedConsumerIT.java b/java/sdk/src/test/java/com/github/copilot/PackagedConsumerIT.java new file mode 100644 index 0000000000..29cb03f487 --- /dev/null +++ b/java/sdk/src/test/java/com/github/copilot/PackagedConsumerIT.java @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import javax.tools.ToolProvider; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class PackagedConsumerIT { + + @Test + void runsStandaloneConsumerWithManifestClasspath(@TempDir Path directory) throws Exception { + Path build = Path.of(System.getProperty("project.build.directory")); + Path library = Files.createDirectory(directory.resolve("lib")); + var dependencies = new ArrayList(); + dependencies.add(build.resolve(System.getProperty("project.build.finalName") + ".jar")); + try (var jars = Files.list(build.resolve("consumer-dependencies"))) { + dependencies.addAll(jars.filter(path -> path.toString().endsWith(".jar")).sorted().toList()); + } + for (Path dependency : dependencies) { + Files.copy(dependency, library.resolve(dependency.getFileName())); + } + + Path source = directory.resolve("Consumer.java"); + Files.writeString(source, """ + import com.github.copilot.CopilotClient; + import com.github.copilot.ConnectionState; + import com.github.copilot.rpc.MessageOptions; + import com.fasterxml.jackson.databind.ObjectMapper; + import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + + public class Consumer { + public static void main(String[] args) throws Exception { + try (var client = new CopilotClient()) { + var mapper = new ObjectMapper().registerModule(new JavaTimeModule()); + var json = mapper.writeValueAsString(new MessageOptions().setPrompt("consumer")); + if (!mapper.readTree(json).get("prompt").asText().equals("consumer") + || client.getState() != ConnectionState.DISCONNECTED) { + throw new AssertionError("Packaged SDK consumer failed"); + } + } + System.out.println("consumer-ok"); + } + } + """); + + String classpath = String.join(File.pathSeparator, + dependencies.stream().map(path -> library.resolve(path.getFileName()).toString()).toList()); + var diagnostics = new ByteArrayOutputStream(); + int compilation = ToolProvider.getSystemJavaCompiler().run(null, diagnostics, diagnostics, "--release", "17", + "-proc:none", "-classpath", classpath, source.toString()); + assertEquals(0, compilation, diagnostics.toString(StandardCharsets.UTF_8)); + + var manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, "Consumer"); + manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, + String.join(" ", dependencies.stream().map(path -> "lib/" + path.getFileName()).toList())); + Path consumerJar = directory.resolve("consumer.jar"); + try (var jar = new JarOutputStream(Files.newOutputStream(consumerJar), manifest)) { + jar.putNextEntry(new JarEntry("Consumer.class")); + Files.copy(directory.resolve("Consumer.class"), jar); + jar.closeEntry(); + } + Files.delete(directory.resolve("Consumer.class")); + + Path java = Path.of(System.getProperty("java.home"), "bin", + System.getProperty("os.name").startsWith("Windows") ? "java.exe" : "java"); + Path output = directory.resolve("output.log"); + ProcessBuilder builder = new ProcessBuilder(java.toString(), "-jar", consumerJar.toString()) + .directory(directory.toFile()).redirectErrorStream(true).redirectOutput(output.toFile()); + builder.environment().remove("COPILOT_SDK_DEFAULT_CONNECTION"); + Process process = builder.start(); + try { + boolean exited = process.waitFor(30, TimeUnit.SECONDS); + String text = Files.readString(output); + assertTrue(exited, "Consumer JVM did not exit. Output:\n" + text); + assertEquals(0, process.exitValue(), text); + assertTrue(text.contains("consumer-ok"), text); + } finally { + if (process.isAlive()) { + process.destroyForcibly().waitFor(30, TimeUnit.SECONDS); + } + } + } +} diff --git a/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java b/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java index 44bff36444..a610007f0e 100644 --- a/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java +++ b/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java @@ -16,8 +16,13 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -43,6 +48,7 @@ * identified by JaCoCo: unknown sessions, missing fields, error paths, and edge * cases for each handler method. */ +@AllowCopilotExperimental class RpcHandlerDispatcherTest { private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); @@ -509,6 +515,217 @@ void userInputRequestHandlerFails() throws Exception { assertEquals(-32603, response.get("error").get("code").asInt()); } + // ===== skillProvider.* tests ===== + + @Test + void skillProviderListAndReadSuccess() throws Exception { + CopilotSession session = createSession("s1"); + session.registerSkillProvider(skillProvider( + () -> CompletableFuture.completedFuture( + List.of(new SkillProviderDescriptor("docs", "Documentation", null, null, "topic"))), + name -> CompletableFuture.completedFuture("# " + name))); + + ObjectNode listParams = MAPPER.createObjectNode(); + listParams.put("sessionId", "s1"); + invokeHandler("skillProvider.list", "60", listParams); + + JsonNode listResponse = readResponse(); + JsonNode descriptor = listResponse.at("/result/skills/0"); + assertEquals("docs", descriptor.path("name").asText()); + assertEquals("Documentation", descriptor.path("description").asText()); + assertEquals("topic", descriptor.path("argumentHint").asText()); + assertFalse(descriptor.has("userInvocable")); + assertFalse(descriptor.has("disableModelInvocation")); + + ObjectNode readParams = MAPPER.createObjectNode(); + readParams.put("sessionId", "s1"); + readParams.put("name", "docs"); + invokeHandler("skillProvider.read", "61", readParams); + + JsonNode readResponse = readResponse(); + assertEquals("# docs", readResponse.at("/result/markdown").asText()); + } + + @Test + void skillProviderNullListReturnsEmptyList() throws Exception { + CopilotSession session = createSession("s1"); + session.registerSkillProvider(skillProvider(() -> CompletableFuture.completedFuture(null), + name -> CompletableFuture.completedFuture("# " + name))); + + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "s1"); + invokeHandler("skillProvider.list", "62", params); + + JsonNode response = readResponse(); + assertTrue(response.at("/result/skills").isArray()); + assertEquals(0, response.at("/result/skills").size()); + } + + @Test + void skillProviderReadNullReturnsNullMarkdown() throws Exception { + CopilotSession session = createSession("s1"); + session.registerSkillProvider(skillProvider(() -> CompletableFuture.completedFuture(List.of()), + name -> CompletableFuture.completedFuture(null))); + + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "s1"); + params.put("name", "missing"); + invokeHandler("skillProvider.read", "63", params); + + JsonNode response = readResponse(); + assertNull(response.get("error")); + assertTrue(response.at("/result").has("markdown")); + assertTrue(response.at("/result/markdown").isNull()); + } + + @Test + void skillProviderFailuresUseStableMessagesWithoutData() throws Exception { + // Keep dispatch and logging outside the socket-read timeout. + var immediateDispatcher = new RpcHandlerDispatcher(sessions, lifecycleEvents::add, Runnable::run, + gitHubTokenProviders); + immediateDispatcher.registerHandlers(rpc); + CopilotSession session = createSession("s1"); + session.registerSkillProvider(skillProvider( + () -> CompletableFuture.failedFuture(new IllegalStateException("secret list failure")), name -> { + throw new IllegalStateException("secret read failure"); + })); + + ObjectNode listParams = MAPPER.createObjectNode(); + listParams.put("sessionId", "s1"); + invokeHandler("skillProvider.list", "64", listParams); + JsonNode listResponse = readResponse(); + assertEquals(-32603, listResponse.at("/error/code").asInt()); + assertEquals("Skill provider listSkills failed", listResponse.at("/error/message").asText()); + assertFalse(listResponse.path("error").has("data")); + + ObjectNode readParams = MAPPER.createObjectNode(); + readParams.put("sessionId", "s1"); + readParams.put("name", "docs"); + invokeHandler("skillProvider.read", "65", readParams); + JsonNode readResponse = readResponse(); + assertEquals(-32603, readResponse.at("/error/code").asInt()); + assertEquals("Skill provider readSkill failed", readResponse.at("/error/message").asText()); + assertFalse(readResponse.path("error").has("data")); + } + + @Test + void skillProviderErrorsForUnknownMissingOrClearedProviderHaveNoData() throws Exception { + ObjectNode unknownParams = MAPPER.createObjectNode(); + unknownParams.put("sessionId", "missing-session"); + invokeHandler("skillProvider.list", "66", unknownParams); + JsonNode unknownResponse = readResponse(); + assertEquals(-32603, unknownResponse.at("/error/code").asInt()); + assertEquals("No skill provider for session: missing-session", unknownResponse.at("/error/message").asText()); + assertFalse(unknownResponse.path("error").has("data")); + + createSession("s1"); + ObjectNode noProviderParams = MAPPER.createObjectNode(); + noProviderParams.put("sessionId", "s1"); + noProviderParams.put("name", "docs"); + invokeHandler("skillProvider.read", "67", noProviderParams); + JsonNode noProviderResponse = readResponse(); + assertEquals(-32603, noProviderResponse.at("/error/code").asInt()); + assertEquals("No skill provider for session: s1", noProviderResponse.at("/error/message").asText()); + assertFalse(noProviderResponse.path("error").has("data")); + + CopilotSession session = sessions.get("s1"); + session.registerSkillProvider(skillProvider(() -> CompletableFuture.completedFuture(List.of()), + name -> CompletableFuture.completedFuture("# " + name))); + session.clearSkillProvider(); + invokeHandler("skillProvider.list", "68", noProviderParams); + JsonNode clearedResponse = readResponse(); + assertEquals(-32603, clearedResponse.at("/error/code").asInt()); + assertEquals("No skill provider for session: s1", clearedResponse.at("/error/message").asText()); + assertFalse(clearedResponse.path("error").has("data")); + } + + @Test + void skillProviderCallIsCancelledByCancelRequest() throws Exception { + CopilotSession session = createSession("s1"); + var entered = new CountDownLatch(1); + var pending = new CompletableFuture>(); + session.registerSkillProvider(skillProvider(() -> { + entered.countDown(); + return pending; + }, name -> CompletableFuture.completedFuture(null))); + + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "s1"); + invokeHandler("skillProvider.list", "69", params); + assertTrue(entered.await(5, TimeUnit.SECONDS)); + dispatcher.handleCancelRequest(MAPPER.createObjectNode().put("id", 69)); + + JsonNode response = readResponse(); + assertEquals(69, response.path("id").asInt()); + assertEquals(-32800, response.at("/error/code").asInt()); + assertTrue(pending.isCancelled()); + } + + @Test + void skillProviderCallCancelledBeforeDispatchIsNotStarted() throws Exception { + CopilotSession session = createSession("s1"); + var calls = new AtomicInteger(); + session.registerSkillProvider(skillProvider(() -> { + calls.incrementAndGet(); + return CompletableFuture.completedFuture(List.of()); + }, name -> CompletableFuture.completedFuture(null))); + var blockedExecutor = new CompletableFuture(); + var cancellingDispatcher = new RpcHandlerDispatcher(sessions, lifecycleEvents::add, + task -> blockedExecutor.thenRun(task), gitHubTokenProviders); + cancellingDispatcher.registerHandlers(rpc); + + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "s1"); + invokeHandler("skillProvider.list", "70", params); + cancellingDispatcher.handleCancelRequest(MAPPER.createObjectNode().put("id", 70)); + blockedExecutor.complete(null); + + assertEquals(-32800, readResponse().at("/error/code").asInt()); + assertEquals(0, calls.get()); + } + + @Test + void skillProviderCallsAreCancelledWhenTheConnectionCloses() throws Exception { + CopilotSession session = createSession("s1"); + var entered = new CountDownLatch(1); + var pending = new CompletableFuture(); + session.registerSkillProvider(skillProvider(() -> CompletableFuture.completedFuture(List.of()), name -> { + entered.countDown(); + return pending; + })); + + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "s1"); + params.put("name", "docs"); + invokeHandler("skillProvider.read", "71", params); + assertTrue(entered.await(5, TimeUnit.SECONDS)); + dispatcher.cancelSkillProviderCalls(); + + assertEquals(-32800, readResponse().at("/error/code").asInt()); + assertTrue(pending.isCancelled()); + } + + @Test + void cancelRequestForAnotherRequestLeavesSkillProviderCallRunning() throws Exception { + CopilotSession session = createSession("s1"); + var entered = new CountDownLatch(1); + var pending = new CompletableFuture(); + session.registerSkillProvider(skillProvider(() -> CompletableFuture.completedFuture(List.of()), name -> { + entered.countDown(); + return pending; + })); + + ObjectNode params = MAPPER.createObjectNode(); + params.put("sessionId", "s1"); + params.put("name", "docs"); + invokeHandler("skillProvider.read", "72", params); + assertTrue(entered.await(5, TimeUnit.SECONDS)); + dispatcher.handleCancelRequest(MAPPER.createObjectNode().put("id", 73)); + pending.complete("# docs"); + + assertEquals("# docs", readResponse().at("/result/markdown").asText()); + } + // ===== hooks.invoke tests ===== @Test @@ -649,4 +866,19 @@ void systemMessageTransformWithKnownSessionNoCallbacks() throws Exception { assertNotNull(resultSections); assertEquals("Original content", resultSections.get("identity").get("content").asText()); } + + private static SkillProvider skillProvider(Supplier>> listSkills, + Function> readSkill) { + return new SkillProvider() { + @Override + public CompletableFuture> listSkills() { + return listSkills.get(); + } + + @Override + public CompletableFuture readSkill(String name) { + return readSkill.apply(name); + } + }; + } } diff --git a/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java b/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java index 774ae10164..c5309a20c0 100644 --- a/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java +++ b/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java @@ -49,8 +49,13 @@ import com.github.copilot.generated.rpc.SessionConnectorsReconnectParams; import com.github.copilot.generated.rpc.SessionConnectorsRefreshParams; import com.github.copilot.generated.rpc.SessionConnectorsRefreshResult; +import com.github.copilot.generated.rpc.SessionMcpListConfiguredResult; +import com.github.copilot.generated.rpc.SessionModelGetReasoningSummariesParams; +import com.github.copilot.generated.rpc.SessionModelGetReasoningSummariesResult; import com.github.copilot.generated.rpc.SessionModelSwitchToParams; +import com.github.copilot.generated.rpc.SessionModelSwitchToRequest; import com.github.copilot.generated.rpc.SessionRpc; +import com.github.copilot.rpc.AgentInfo; /** * Unit tests for the generated RPC wrapper classes ({@link ServerRpc} and @@ -188,6 +193,60 @@ void serverRpc_mcp_discover_passes_params() { // ── SessionRpc tests ────────────────────────────────────────────────────── + @ParameterizedTest + @CsvSource({"true,false", "false,true", "null,null"}) + void sessionRpc_reasoning_summaries_accepts_only_host_state(String persisted, String visible) { + var stub = new StubCaller(); + var session = new SessionRpc(stub, "reasoning-session"); + Boolean persistedShowReasoning = "null".equals(persisted) ? null : Boolean.valueOf(persisted); + Boolean summariesVisible = "null".equals(visible) ? null : Boolean.valueOf(visible); + var params = new SessionModelGetReasoningSummariesParams(persistedShowReasoning, summariesVisible); + + assertNull(params.sessionId()); + session.model.getReasoningSummaries(params).join(); + + assertEquals(1, stub.calls.size()); + var call = stub.calls.get(0); + assertEquals("session.model.getReasoningSummaries", call.method()); + assertEquals(SessionModelGetReasoningSummariesResult.class, call.resultType()); + var payload = assertInstanceOf(JsonNode.class, call.params()); + var expected = new ObjectMapper().createObjectNode().put("sessionId", "reasoning-session"); + if (persistedShowReasoning != null) { + expected.put("persistedShowReasoning", persistedShowReasoning); + } + if (summariesVisible != null) { + expected.put("summariesVisible", summariesVisible); + } + assertEquals(expected, payload); + } + + @Test + @AllowCopilotExperimental + void sessionRpc_mcp_listConfigured_preserves_runtime_lifecycle() throws Exception { + var stub = new StubCaller(); + stub.nextResult = new ObjectMapper().readValue(""" + { + "servers": [ + {"name":"cold","enabled":true,"live":{"status":"not_configured"}}, + {"name":"old-connection","enabled":false,"live":{"status":"connected"}}, + {"name":"auth","enabled":true,"live":{"status":"needs-auth"}}, + {"name":"stopped","enabled":true,"live":{"status":"stopped"}}, + {"name":"failed","enabled":true,"live":{"status":"failed","error":"connection failed"}} + ] + } + """, SessionMcpListConfiguredResult.class); + var session = new SessionRpc(stub, "session-mcp"); + + var inventory = session.mcp.listConfigured().get(); + + assertEquals(List.of("not_configured", "connected", "needs-auth", "stopped", "failed"), + inventory.servers().stream().map(server -> server.live().status().getValue()).toList()); + assertFalse(inventory.servers().get(1).enabled()); + assertEquals("connection failed", inventory.servers().get(4).live().error()); + assertEquals(List.of(new StubCaller.Call("session.mcp.listConfigured", Map.of("sessionId", "session-mcp"), + SessionMcpListConfiguredResult.class)), stub.calls); + } + @Test void sessionRpc_instantiates_with_all_namespace_fields() { var stub = new StubCaller(); @@ -445,8 +504,9 @@ void sessionRpc_model_switchTo_merges_sessionId_with_extra_params() { var switchParams = new SessionModelSwitchToParams(null, "gpt-5", null, null, null, null, null, null, null, null, null, null, null, null, null, null); session.model.switchTo(switchParams); + session.model.switchTo(new SessionModelSwitchToRequest("gpt-5").setProviderId("catalog-provider")); - assertEquals(1, stub.calls.size()); + assertEquals(2, stub.calls.size()); assertEquals("session.model.switchTo", stub.calls.get(0).method()); // Params should be a JsonNode containing both sessionId and modelId @@ -454,7 +514,12 @@ void sessionRpc_model_switchTo_merges_sessionId_with_extra_params() { assertInstanceOf(com.fasterxml.jackson.databind.node.ObjectNode.class, params); var node = (com.fasterxml.jackson.databind.node.ObjectNode) params; assertEquals("sess-xyz", node.get("sessionId").asText()); + assertFalse(node.has("providerId")); assertEquals("gpt-5", node.get("modelId").asText()); + var providerRequest = (com.fasterxml.jackson.databind.node.ObjectNode) stub.calls.get(1).params(); + assertEquals("sess-xyz", providerRequest.get("sessionId").asText()); + assertEquals("catalog-provider", providerRequest.get("providerId").asText()); + assertEquals("gpt-5", providerRequest.get("modelId").asText()); } @Test @@ -540,6 +605,56 @@ void serverRpc_account_getQuota_invokes_correct_method() { // RpcHandlerDispatcherTest) to construct a real CopilotSession and verify // that getRpc() returns a correctly wired SessionRpc. + @ParameterizedTest + @ValueSource(strings = {"list", "getCurrent", "select"}) + void copilotSession_agent_methods_deserialize_scoped_hooks(String method) throws Exception { + var mapper = JsonRpcClient.getObjectMapper(); + var agentJson = mapper.readTree(""" + { + "name": "hook-agent", + "displayName": "Hook Agent", + "description": "Agent with scoped hooks", + "hooks": { + "preToolUse": [{"type":"command","bash":"echo scoped-hook","timeoutSec":10}], + "sessionStart": [{"type":"command","bash":"echo started"}] + } + } + """); + try (var sockets = new SocketPair()) { + var stub = sockets.stubServer(); + var session = new CopilotSession("sess-agent-hooks", sockets.client()); + try { + CompletableFuture> future = switch (method) { + case "list" -> session.listAgents(); + case "getCurrent" -> session.getCurrentAgent().thenApply(List::of); + case "select" -> session.selectAgent("hook-agent").thenApply(List::of); + default -> throw new IllegalArgumentException(method); + }; + var request = stub.readOneMessage(); + assertEquals("session.agent." + method, request.get("method").asText()); + assertEquals("sess-agent-hooks", request.get("params").get("sessionId").asText()); + if ("select".equals(method)) { + assertEquals("hook-agent", request.get("params").get("name").asText()); + } + var result = mapper.createObjectNode(); + if ("list".equals(method)) { + result.putArray("agents").add(agentJson); + } else { + result.set("agent", agentJson); + } + stub.respond(request, result); + + var agents = future.get(3, TimeUnit.SECONDS); + assertEquals(1, agents.size()); + assertEquals("hook-agent", agents.get(0).getName()); + assertNotNull(agents.get(0).getHooks()); + assertEquals(agentJson.get("hooks"), mapper.valueToTree(agents.get(0).getHooks())); + } finally { + session.forceStopLocally(); + } + } + } + @Test void copilotSession_getRpc_returns_non_null_session_rpc() throws Exception { try (var sockets = new SocketPair()) { diff --git a/java/sdk/src/test/java/com/github/copilot/RuntimeHostIT.java b/java/sdk/src/test/java/com/github/copilot/RuntimeHostIT.java index 43b286da48..ab00b483c6 100644 --- a/java/sdk/src/test/java/com/github/copilot/RuntimeHostIT.java +++ b/java/sdk/src/test/java/com/github/copilot/RuntimeHostIT.java @@ -46,6 +46,8 @@ private static final class Application { final E2ETestContext context; final CopilotClient client; volatile CopilotSession session; + volatile String createSessionId; + volatile String resumeSessionId; final AtomicInteger creates = new AtomicInteger(); final AtomicInteger resumes = new AtomicInteger(); final AtomicInteger toolCalls = new AtomicInteger(); @@ -99,14 +101,24 @@ AhpHostOptions options() { creates.incrementAndGet(); assertFalse(request.cancellation().toCompletableFuture().isDone()); assertEquals(context.getWorkDir().toString(), request.config().getWorkingDirectory()); - return client.createSession(configure(request.config())).thenApply(value -> session = value); + createSessionId = request.config().getSessionId(); + assertNotNull(createSessionId); + assertFalse(createSessionId.isEmpty()); + return client.createSession(configure(request.config())).thenApply(value -> { + assertEquals(createSessionId, value.getSessionId()); + return session = value; + }); }).setResumeSession(request -> { resumes.incrementAndGet(); assertFalse(request.cancellation().toCompletableFuture().isDone()); assertEquals(false, request.config().getContinuePendingWork().orElseThrow()); assertEquals(context.getWorkDir().toString(), request.config().getWorkingDirectory()); + resumeSessionId = request.sessionId(); return client.resumeSession(request.sessionId(), configure(request.config())) - .thenApply(value -> session = value); + .thenApply(value -> { + assertEquals(resumeSessionId, value.getSessionId()); + return session = value; + }); }).setOnSessionReleased(value -> { releases.add(value); released.complete(null); @@ -174,13 +186,14 @@ void createsOrPublishesExactApplicationSession(boolean publish) throws Exception } else { sessionId = ahp.request(Map.of("op", "create", "clientId", clientId, "workDir", context.getWorkDir().toString())).get("sessionId").asText(); - assertEquals(sessionId, app.session.getSessionId()); + assertEquals(app.createSessionId, app.session.getSessionId()); + assertNotEquals(sessionId, app.session.getSessionId()); assertEquals(1, app.creates.get()); } var response = ahp.request( Map.of("op", "turn", "clientId", clientId, "sessionId", sessionId, "prompt", TOOL_PROMPT)); assertTrue(response.get("text").asText().contains("MAGIC_hello_42")); - app.assertCallbacks(sessionId); + app.assertCallbacks(app.session.getSessionId()); await(CompletableFuture.allOf(host.dispose(), host.dispose())); stopped(ahp, host, clientId); if (publish) { @@ -213,6 +226,9 @@ void resumesAfterRuntimeRestartAndComposesTools() throws Exception { sessionId = ahp.request(Map.of("op", "create", "clientId", clientId, "workDir", context.getWorkDir().toString(), "clientTools", true)).get("sessionId").asText(); original = app.session; + assertEquals(1, app.creates.get()); + assertEquals(app.createSessionId, original.getSessionId()); + assertNotEquals(sessionId, original.getSessionId()); assertTrue(ahp.request(Map.of("op", "turn", "clientId", clientId, "sessionId", sessionId, "prompt", "What is 2+2?")).get("text").asText().contains("4")); await(host.dispose()); @@ -232,14 +248,15 @@ void resumesAfterRuntimeRestartAndComposesTools() throws Exception { assertEquals("What is 2+2?", attached.get("history").get(0).get("message").get("text").asText()); assertEquals(0, app.creates.get()); assertEquals(1, app.resumes.get()); - assertEquals(sessionId, app.session.getSessionId()); + assertEquals(original.getSessionId(), app.resumeSessionId); + assertEquals(original.getSessionId(), app.session.getSessionId()); assertNotSame(original, app.session); var response = ahp.request(Map.of("op", "turn", "clientId", clientId, "sessionId", sessionId, "prompt", COMPOSED_PROMPT, "clientTools", true)); assertTrue(response.get("text").asText().contains("MAGIC_hello_42")); assertTrue(response.get("text").asText().contains("CLIENT_ECHO_ping")); assertEquals(1, response.get("clientToolCalls").asInt()); - app.assertCallbacks(sessionId); + app.assertCallbacks(original.getSessionId()); await(host.dispose()); stopped(ahp, host, clientId); app.assertReleased(); diff --git a/java/sdk/src/test/java/com/github/copilot/SessionAutoTierEventTest.java b/java/sdk/src/test/java/com/github/copilot/SessionAutoTierEventTest.java index 4378c105cd..ef7034c455 100644 --- a/java/sdk/src/test/java/com/github/copilot/SessionAutoTierEventTest.java +++ b/java/sdk/src/test/java/com/github/copilot/SessionAutoTierEventTest.java @@ -30,11 +30,11 @@ class SessionAutoTierEventTest { private static final ObjectMapper MAPPER = JsonRpcClient.getObjectMapper(); @ParameterizedTest - @CsvSource({"session.start,EFFICIENCY,efficiency", "session.start,BALANCE,balance", - "session.start,INTELLIGENCE,intelligence", "session.start,FAST,fast", - "session.resume,EFFICIENCY,efficiency", "session.resume,BALANCE,balance", - "session.resume,INTELLIGENCE,intelligence", "session.resume,FAST,fast"}) - void canonicalAutoTierRoundTrips(String type, AutoTier tier, String value) throws Exception { + @CsvSource({"session.start,efficiency", "session.start,balance", "session.start,intelligence", "session.start,fast", + "session.start,premium-v2", "session.resume,efficiency", "session.resume,balance", + "session.resume,intelligence", "session.resume,fast", "session.resume,premium-v2"}) + void canonicalAutoTierRoundTrips(String type, String value) throws Exception { + AutoTier tier = AutoTier.fromValue(value); String json = """ {"type":"%s","data":{"selectedModel":"auto","autoTier":"%s"}} """.formatted(type, value); diff --git a/java/sdk/src/test/java/com/github/copilot/SessionAutoTierSwitchTest.java b/java/sdk/src/test/java/com/github/copilot/SessionAutoTierSwitchTest.java index a1c5dd2f44..96b9bf0319 100644 --- a/java/sdk/src/test/java/com/github/copilot/SessionAutoTierSwitchTest.java +++ b/java/sdk/src/test/java/com/github/copilot/SessionAutoTierSwitchTest.java @@ -33,6 +33,45 @@ @AllowCopilotExperimental class SessionAutoTierSwitchTest { + @Test + void customTierRoundTripsAcrossConvenienceAndGeneratedApis() throws Exception { + ObjectMapper mapper = JsonRpcClient.getObjectMapper(); + AutoTier tier = AutoTier.fromValue("premium-v2"); + assertEquals("\"premium-v2\"", mapper.writeValueAsString(tier)); + assertEquals(tier, mapper.readValue("\"premium-v2\"", AutoTier.class)); + var generated = mapper.readValue("\"premium-v2\"", com.github.copilot.generated.rpc.AutoTier.class); + assertEquals("premium-v2", generated.getValue()); + assertEquals("\"premium-v2\"", mapper.writeValueAsString(generated)); + assertEquals(AutoTier.BALANCE, AutoTier.fromValue("balance")); + } + + @Test + void legacy_model_switch_preserves_reasoning_and_omits_provider() throws Exception { + try (var sockets = new SocketPair()) { + var session = new CopilotSession("sess-legacy", sockets.client()); + session.setModel("gpt-5", "high"); + var params = sockets.stubServer().readOneMessage().get("params"); + assertEquals("gpt-5", params.get("modelId").asText()); + assertEquals("high", params.get("reasoningEffort").asText()); + assertFalse(params.has("providerId")); + assertFalse(params.has("autoTier")); + } + } + + @Test + void model_switch_with_summary_preserves_its_wire_fields() throws Exception { + try (var sockets = new SocketPair()) { + var session = new CopilotSession("sess-summary", sockets.client()); + session.setModel("gpt-5", "high", "concise", null); + var params = sockets.stubServer().readOneMessage().get("params"); + assertEquals("gpt-5", params.get("modelId").asText()); + assertEquals("high", params.get("reasoningEffort").asText()); + assertEquals("concise", params.get("reasoningSummary").asText()); + assertFalse(params.has("providerId")); + assertFalse(params.has("autoTier")); + } + } + @Test void setModel_omits_autoTier_when_no_preference_is_requested() throws Exception { try (var sockets = new SocketPair()) { diff --git a/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java b/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java index 46b71d7d3f..64c32b4a74 100644 --- a/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java +++ b/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java @@ -35,6 +35,7 @@ import com.github.copilot.generated.SessionIdleEvent; import com.github.copilot.generated.SessionErrorEvent; import com.github.copilot.generated.SessionMode; +import com.github.copilot.generated.SessionResumeEvent; import com.github.copilot.generated.SessionStartEvent; import com.github.copilot.generated.rpc.SessionToolsGetCurrentMetadataResult; import com.github.copilot.rpc.MessageOptions; @@ -230,6 +231,24 @@ void testTypedEventHandler() { assertEquals("Second message", receivedMessages.get(1).getData().content()); } + @Test + void testSendReturnsAfterRpcAcceptanceWithoutWaitingForIdle() throws Exception { + var rpc = mock(JsonRpcClient.class); + when(rpc.invoke(eq("session.send"), any(), eq(SendMessageResponse.class))) + .thenReturn(CompletableFuture.completedFuture(new SendMessageResponse("message-1"))); + session = createTestSession(rpc); + var events = new ArrayList(); + session.on(events::add); + + session.send("hello").get(1, TimeUnit.SECONDS); + + verify(rpc).invoke(eq("session.send"), any(), eq(SendMessageResponse.class)); + assertTrue(events.isEmpty()); + dispatchEvent(createAssistantMessageEvent("done")); + dispatchEvent(createSessionIdleEvent()); + assertEquals(List.of("assistant.message", "session.idle"), events.stream().map(SessionEvent::getType).toList()); + } + @Test void testSendAndWaitSkipsAutopilotContinuationIdle() throws Exception { var rpc = mock(JsonRpcClient.class); @@ -276,8 +295,8 @@ void testSendAndWaitIgnoresChildEvents() throws Exception { dispatchEvent(childMessage); var childError = new SessionErrorEvent(); childError.setAgentId("child-1"); - childError.setData(new SessionErrorEvent.SessionErrorEventData("query", null, null, "child failed", null, - null, null, null, null, null)); + childError.setData(new SessionErrorEvent.SessionErrorEventData("query", null, null, null, null, + "child failed", null, null, null, null, null, null)); dispatchEvent(childError); var childIdle = createSessionIdleEvent(); childIdle.setAgentId("child-1"); @@ -385,9 +404,7 @@ void testHandlerReceivesCorrectEventData() { capturedSessionId.set(start.getData().sessionId()); }); - SessionStartEvent startEvent = createSessionStartEvent(); - startEvent.setData(new SessionStartEvent.SessionStartEventData("my-session-123", null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null)); + SessionStartEvent startEvent = createSessionStartEvent("my-session-123"); dispatchEvent(startEvent); AssistantMessageEvent msgEvent = createAssistantMessageEvent("Test content"); @@ -397,6 +414,17 @@ void testHandlerReceivesCorrectEventData() { assertEquals("Test content", capturedContent.get()); } + @Test + void testLegacyLifecycleEventConstructorsRemainAvailable() { + var start = new SessionStartEvent.SessionStartEventData("session", null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null); + var resume = new SessionResumeEvent.SessionResumeEventData(null, 0L, null, null, null, null, null, null, null, + null, null, null, null, null, null, null); + + assertEquals("session", start.sessionId()); + assertEquals(0L, resume.eventCount()); + } + @Test void testHandlerExceptionDoesNotBreakOtherHandlers() { var handler2Events = new ArrayList(); @@ -1071,9 +1099,9 @@ private SessionStartEvent createSessionStartEvent(String sessionId) { private AssistantMessageEvent createAssistantMessageEvent(String content) { var event = new AssistantMessageEvent(); - var data = new AssistantMessageEvent.AssistantMessageEventData(null, null, null, content, null, null, null, + var data = new AssistantMessageEvent.AssistantMessageEventData(null, null, null, null, content, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null); + null, null); event.setData(data); return event; } diff --git a/java/sdk/src/test/java/com/github/copilot/SessionEventsE2ETest.java b/java/sdk/src/test/java/com/github/copilot/SessionEventsE2ETest.java index 8c8fc154aa..40a23c5cf3 100644 --- a/java/sdk/src/test/java/com/github/copilot/SessionEventsE2ETest.java +++ b/java/sdk/src/test/java/com/github/copilot/SessionEventsE2ETest.java @@ -11,7 +11,7 @@ import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -67,7 +67,7 @@ void testShouldReceiveSessionEvents_assistantTurnEvents() throws Exception { // Use existing session snapshot that emits turn events ctx.configureForTest("session", "should_receive_session_events"); - var allEvents = new ArrayList(); + var allEvents = new CopyOnWriteArrayList(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client @@ -109,7 +109,7 @@ void testShouldReceiveSessionEvents_userMessageEvent() throws Exception { // Use existing session snapshot ctx.configureForTest("session", "should_receive_session_events"); - var userMessages = new ArrayList(); + var userMessages = new CopyOnWriteArrayList(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client @@ -135,8 +135,8 @@ void testInvokesBuiltInTools_toolExecutionCompleteEvent() throws Exception { // Use existing tools snapshot for built-in tool invocation ctx.configureForTest("tools", "invokes_built_in_tools"); - var toolStarts = new ArrayList(); - var toolCompletes = new ArrayList(); + var toolStarts = new CopyOnWriteArrayList(); + var toolCompletes = new CopyOnWriteArrayList(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client @@ -175,7 +175,7 @@ void testShouldReceiveSessionEvents_assistantUsageEvent() throws Exception { // Use existing session snapshot ctx.configureForTest("session", "should_receive_session_events"); - var usageEvents = new ArrayList(); + var usageEvents = new CopyOnWriteArrayList(); try (CopilotClient client = ctx.createClient()) { CopilotSession session = client @@ -206,7 +206,7 @@ void testShouldReceiveSessionEvents_sessionIdleAfterMessage() throws Exception { // Use existing session snapshot ctx.configureForTest("session", "should_receive_session_events"); - var allEvents = new ArrayList(); + var allEvents = new CopyOnWriteArrayList(); var idleEntered = new CountDownLatch(1); var releaseIdle = new CountDownLatch(1); var idleCallbackCompleted = new AtomicBoolean(); @@ -274,7 +274,7 @@ void testInvokesBuiltInTools_eventOrderDuringToolExecution() throws Exception { // Use existing tools snapshot for built-in tool invocation ctx.configureForTest("tools", "invokes_built_in_tools"); - var eventTypes = new ArrayList(); + var eventTypes = new CopyOnWriteArrayList(); // Track this listener's receipt of session.idle explicitly. var idleReceived = new java.util.concurrent.CompletableFuture(); diff --git a/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java b/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java index c7cb1be6bc..09b036c6fc 100644 --- a/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java +++ b/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java @@ -6,6 +6,8 @@ import static org.junit.jupiter.api.Assertions.*; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -100,6 +102,71 @@ void clearingTranscriptRecoveryRestoresRuntimeDefaultInAllModes() throws Excepti } } + @Test + void customizationDirectoriesArePreservedOnCreateAndResume() throws Exception { + var mapper = JsonRpcClient.getObjectMapper(); + for (int kind = 0; kind < 3; kind++) { + List roots = kind == 0 ? null : kind == 1 ? List.of() : List.of("relative-root", "other-root"); + var directories = new HashMap>(); + for (var type : List.of("skill", "agent", "instruction", "hook")) { + directories.put(type + "Directories", + roots == null ? null : roots.stream().map(root -> root + "-" + type).toList()); + } + var create = SessionRequestBuilder.buildCreateRequest( + new SessionConfig().setWorkingDirectory("request-cwd").setEnableConfigDiscovery(false) + .setEnableFileHooks(false).setSkillDirectories(directories.get("skillDirectories")) + .setAgentDirectories(directories.get("agentDirectories")) + .setInstructionDirectories(directories.get("instructionDirectories")) + .setHookDirectories(directories.get("hookDirectories")), + "created"); + var resume = SessionRequestBuilder.buildResumeRequest("resumed", + new ResumeSessionConfig().setWorkingDirectory("resume-cwd").setEnableConfigDiscovery(false) + .setEnableFileHooks(false).setSkillDirectories(directories.get("skillDirectories")) + .setAgentDirectories(directories.get("agentDirectories")) + .setInstructionDirectories(directories.get("instructionDirectories")) + .setHookDirectories(directories.get("hookDirectories"))); + for (var request : List.of(create, resume)) { + var wire = mapper.readTree(mapper.writeValueAsBytes(request)); + for (var entry : directories.entrySet()) { + if (entry.getValue() == null) { + assertFalse(wire.has(entry.getKey()), wire.toString()); + } else { + assertEquals(mapper.valueToTree(entry.getValue()), wire.get(entry.getKey())); + } + } + assertFalse(wire.path("enableConfigDiscovery").asBoolean(true)); + assertFalse(wire.path("enableFileHooks").asBoolean(true)); + assertFalse(wire.has("additionalDirectories")); + assertFalse(wire.has("customAgents")); + assertFalse(wire.path("hooks").asBoolean()); + } + } + } + + @Test + void customizationDirectoryClonesOwnTheirLists() { + var agents = new ArrayList<>(List.of("agents")); + var hooks = new ArrayList<>(List.of("hooks")); + var create = new SessionConfig().setAgentDirectories(agents).setHookDirectories(hooks); + var resume = new ResumeSessionConfig().setAgentDirectories(agents).setHookDirectories(hooks); + var createClone = create.clone(); + var resumeClone = resume.clone(); + agents.add("added-agents"); + hooks.add("added-hooks"); + assertEquals(List.of("agents"), create.getAgentDirectories()); + assertEquals(List.of("hooks"), create.getHookDirectories()); + assertEquals(List.of("agents"), resume.getAgentDirectories()); + assertEquals(List.of("hooks"), resume.getHookDirectories()); + assertEquals(List.of("agents"), createClone.getAgentDirectories()); + assertEquals(List.of("hooks"), createClone.getHookDirectories()); + assertEquals(List.of("agents"), resumeClone.getAgentDirectories()); + assertEquals(List.of("hooks"), resumeClone.getHookDirectories()); + assertThrows(UnsupportedOperationException.class, () -> createClone.getAgentDirectories().add("mutation")); + assertThrows(UnsupportedOperationException.class, () -> resumeClone.getHookDirectories().add("mutation")); + assertThrows(UnsupportedOperationException.class, () -> create.getAgentDirectories().add("mutation")); + assertThrows(UnsupportedOperationException.class, () -> resume.getHookDirectories().add("mutation")); + } + // ========================================================================= // buildCreateRequest // ========================================================================= @@ -111,6 +178,7 @@ void testBuildCreateRequestNullConfig() { assertNull(request.getModel()); assertTrue(request.getRequestPermission(), "requestPermission should be true even for null config"); assertEquals("direct", request.getEnvValueMode(), "envValueMode should be 'direct' even for null config"); + assertNull(request.getHasSkillProvider()); } @Test @@ -162,6 +230,36 @@ void askUserVariantDefaultsToOmittedLegacyBehavior() throws Exception { assertFalse(mapper.readTree(mapper.writeValueAsBytes(resumeRequest)).has("askUserVariant")); } + @Test + @AllowCopilotExperimental + void skillProviderFlagIsForwardedAndSerializedForCreateAndResume() throws Exception { + SkillProvider provider = testSkillProvider(); + var mapper = JsonRpcClient.getObjectMapper(); + + var createRequest = SessionRequestBuilder.buildCreateRequest(new SessionConfig().setSkillProvider(provider), + "skill-provider-create"); + var resumeRequest = SessionRequestBuilder.buildResumeRequest("skill-provider-resume", + new ResumeSessionConfig().setSkillProvider(provider)); + + assertTrue(createRequest.getHasSkillProvider()); + assertTrue(resumeRequest.getHasSkillProvider()); + assertTrue(mapper.readTree(mapper.writeValueAsBytes(createRequest)).path("hasSkillProvider").asBoolean()); + assertTrue(mapper.readTree(mapper.writeValueAsBytes(resumeRequest)).path("hasSkillProvider").asBoolean()); + } + + @Test + void skillProviderFlagIsOmittedWhenUnset() throws Exception { + var mapper = JsonRpcClient.getObjectMapper(); + var createRequest = SessionRequestBuilder.buildCreateRequest(new SessionConfig(), "skill-provider-create"); + var resumeRequest = SessionRequestBuilder.buildResumeRequest("skill-provider-resume", + new ResumeSessionConfig()); + + assertNull(createRequest.getHasSkillProvider()); + assertNull(resumeRequest.getHasSkillProvider()); + assertFalse(mapper.readTree(mapper.writeValueAsBytes(createRequest)).has("hasSkillProvider")); + assertFalse(mapper.readTree(mapper.writeValueAsBytes(resumeRequest)).has("hasSkillProvider")); + } + @Test void diagnosticsAreForwardedAndOmittedForCreateAndColdResume() throws Exception { var mapper = JsonRpcClient.getObjectMapper(); @@ -399,6 +497,7 @@ void testBuildResumeRequestNullConfig() { assertNull(request.getContinuePendingWork()); assertTrue(request.getRequestPermission(), "requestPermission should be true even for null config"); assertEquals("direct", request.getEnvValueMode(), "envValueMode should be 'direct' even for null config"); + assertNull(request.getHasSkillProvider()); } @Test @@ -850,6 +949,17 @@ void configureSessionWithNullConfig_returnsEarly() { assertDoesNotThrow(() -> SessionRequestBuilder.configureSession(session, (SessionConfig) null)); } + @Test + @AllowCopilotExperimental + void configureSessionWithSkillProvider_registersProvider() { + CopilotSession session = new CopilotSession("session-1", null); + SkillProvider provider = testSkillProvider(); + + SessionRequestBuilder.configureSession(session, new SessionConfig().setSkillProvider(provider)); + + assertSame(provider, session.getSkillProvider()); + } + @Test void configureSessionWithCommands_registersCommands() { CopilotSession session = new CopilotSession("session-1", null); @@ -922,6 +1032,17 @@ void configureResumedSessionWithOnEvent_registersEventHandler() { SessionRequestBuilder.configureSession(session, config); } + @Test + @AllowCopilotExperimental + void configureResumedSessionWithSkillProvider_registersProvider() { + CopilotSession session = new CopilotSession("session-1", null); + SkillProvider provider = testSkillProvider(); + + SessionRequestBuilder.configureSession(session, new ResumeSessionConfig().setSkillProvider(provider)); + + assertSame(provider, session.getSkillProvider()); + } + @Test void testBuildCreateRequestWithDefaultAgent() { var defaultAgent = new DefaultAgentConfig().setExcludedTools(List.of("secret_tool")); @@ -1300,4 +1421,19 @@ void githubMcpToolConfigIsMappedAndSerializedForCreateAndResume() throws Excepti mapper.writeValueAsString(SessionRequestBuilder.buildCreateRequest(new SessionConfig(), "session-2")) .contains("\"githubMcpToolConfig\"")); } + + @AllowCopilotExperimental + private static SkillProvider testSkillProvider() { + return new SkillProvider() { + @Override + public CompletableFuture> listSkills() { + return CompletableFuture.completedFuture(List.of()); + } + + @Override + public CompletableFuture readSkill(String name) { + return CompletableFuture.completedFuture(null); + } + }; + } } diff --git a/java/sdk/src/test/java/com/github/copilot/SetToolsTest.java b/java/sdk/src/test/java/com/github/copilot/SetToolsTest.java index 6f4723ce58..267d1375e4 100644 --- a/java/sdk/src/test/java/com/github/copilot/SetToolsTest.java +++ b/java/sdk/src/test/java/com/github/copilot/SetToolsTest.java @@ -173,6 +173,32 @@ void cancellingWhileQueuedSendsNothing() throws Exception { assertNull(session.getTool("queued")); } + @Test + void closeRejectsLateAcknowledgementsAndQueuedReplacements() throws Exception { + var accepted = new CompletableFuture(); + var requests = captureSetToolsRequests(accepted); + when(rpc.invoke(eq("session.detach"), any(), eq(CopilotSession.SessionDetachResponse.class))) + .thenReturn(CompletableFuture.completedFuture(new CopilotSession.SessionDetachResponse(true, null))); + + var pending = session.setTools(List.of(tool("pending", "Pending", "first", new CopyOnWriteArrayList<>()))); + var queued = session.setTools(List.of(tool("queued", "Queued", "second", new CopyOnWriteArrayList<>()))); + assertEquals(1, requests.size(), "Only the admitted replacement may reach the RPC boundary"); + assertFalse(pending.isDone()); + assertFalse(queued.isDone()); + + session.close(); + assertTrue(accepted.complete(null), "Acknowledge the admitted replacement only after retirement"); + + var pendingError = assertThrows(ExecutionException.class, () -> pending.get(1, TimeUnit.SECONDS)); + var queuedError = assertThrows(ExecutionException.class, () -> queued.get(1, TimeUnit.SECONDS)); + assertInstanceOf(IllegalStateException.class, pendingError.getCause()); + assertInstanceOf(IllegalStateException.class, queuedError.getCause()); + assertEquals("Session is closed", pendingError.getCause().getMessage()); + assertEquals("Session is closed", queuedError.getCause().getMessage()); + assertEquals(1, requests.size(), "A replacement queued before retirement must not start afterwards"); + assertThrows(IllegalStateException.class, () -> session.setTools(List.of())); + } + private List captureSetToolsRequests(CompletableFuture result) { var requests = new ArrayList(); when(rpc.invoke(eq("session.tools.set"), any(), eq(Void.class))).thenAnswer(invocation -> { diff --git a/java/sdk/src/test/java/com/github/copilot/SkillProviderTest.java b/java/sdk/src/test/java/com/github/copilot/SkillProviderTest.java new file mode 100644 index 0000000000..7a4e6f3329 --- /dev/null +++ b/java/sdk/src/test/java/com/github/copilot/SkillProviderTest.java @@ -0,0 +1,421 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot; + +import static org.junit.jupiter.api.Assertions.*; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.github.copilot.generated.AssistantMessageEvent; +import com.github.copilot.generated.SessionEvent; +import com.github.copilot.generated.ToolExecutionCompleteEvent; +import com.github.copilot.generated.rpc.Skill; +import com.github.copilot.generated.rpc.SkillSource; +import com.github.copilot.rpc.CloudSessionOptions; +import com.github.copilot.rpc.MessageOptions; +import com.github.copilot.rpc.PermissionHandler; +import com.github.copilot.rpc.ResumeSessionConfig; +import com.github.copilot.rpc.SessionConfig; + +@AllowCopilotExperimental +class SkillProviderTest { + + private static E2ETestContext ctx; + + @BeforeAll + static void setup() throws Exception { + ctx = E2ETestContext.create(); + } + + @AfterAll + static void teardown() throws Exception { + if (ctx != null) { + ctx.close(); + } + } + + @Test + void should_load_provider_skill_lazily_through_skill_tool() throws Exception { + ctx.configureForTest("skill_provider", "should_load_provider_skill_lazily_through_skill_tool"); + + var provider = new TestSkillProvider( + List.of(skill("provider-lookup", "Reports the provider lookup verification word.", + "# Provider lookup\n\nThe verification word is TANGERINE_QUARTZ_19. Reply with it.\n"))); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession session = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(provider)) + .get(30, TimeUnit.SECONDS); + + try { + Skill listed = session.getRpc().skills.list().get(30, TimeUnit.SECONDS).skills().stream() + .filter(s -> "provider-lookup".equals(s.name())).findFirst().orElse(null); + assertNotNull(listed, "Expected provider-lookup to be listed"); + assertEquals(SkillSource.SDK, listed.source()); + assertTrue(listed.enabled()); + assertEquals("", listed.path() == null ? "" : listed.path()); + assertEquals(List.of(), provider.reads()); + + AssistantMessageEvent message = session.sendAndWait(new MessageOptions().setPrompt( + "Use the skill tool to load the provider-lookup skill, then reply with its verification word."), + 60_000).get(90, TimeUnit.SECONDS); + + assertEquals(List.of("provider-lookup"), provider.reads()); + // Validate the final assistant response arrived (guards against truncated + // captures) + assertTrue(assistantText(message).contains("TANGERINE_QUARTZ_19")); + } finally { + session.close(); + } + } + } + + @Test + void should_load_provider_and_file_based_skills_together() throws Exception { + ctx.configureForTest("skill_provider", "should_load_provider_and_file_based_skills_together"); + + Path skillsDir = ctx.getWorkDir().resolve("file-skills"); + Files.createDirectories(skillsDir.resolve("file-notes")); + Files.writeString(skillsDir.resolve("file-notes").resolve("SKILL.md"), + "---\nname: file-notes\ndescription: Reports the file notes verification word.\n---\n\nThe file notes verification word is MAPLE_FALCON_27.\n"); + + var provider = new TestSkillProvider(List.of(skill("provider-audit", + "Reports the provider audit verification word.", + "---\nname: provider-audit\nallowed-tools: view\n---\n\nThe provider audit verification word is COBALT_HERON_58.\n"))); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession session = client + .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setSkillDirectories(List.of(skillsDir.toString())).setSkillProvider(provider)) + .get(30, TimeUnit.SECONDS); + + try { + List skills = session.getRpc().skills.list().get(30, TimeUnit.SECONDS).skills(); + Skill fileSkill = findSkill(skills, "file-notes"); + Skill providerSkill = findSkill(skills, "provider-audit"); + assertNotNull(fileSkill, "Expected file-notes to be listed"); + assertNotEquals(SkillSource.SDK, fileSkill.source()); + assertNotNull(fileSkill.path()); + assertNotNull(providerSkill, "Expected provider-audit to be listed"); + assertEquals(SkillSource.SDK, providerSkill.source()); + + AssistantMessageEvent message = session.sendAndWait(new MessageOptions().setPrompt( + "Use the skill tool to load the file-notes skill and the provider-audit skill, then reply with both verification words."), + 60_000).get(90, TimeUnit.SECONDS); + + assertEquals(List.of("provider-audit"), provider.reads()); + assertTrue(assistantText(message).contains("MAPLE_FALCON_27")); + // Validate the final assistant response arrived (guards against truncated + // captures) + assertTrue(assistantText(message).contains("COBALT_HERON_58")); + } finally { + session.close(); + } + } + } + + @Test + void should_rebind_skill_provider_on_resume() throws Exception { + ctx.configureForTest("skill_provider", "should_rebind_skill_provider_on_resume"); + + var original = new TestSkillProvider(List.of(skill("rebind-check", "Reports the rebind verification word.", + "The rebind verification word is AMBER_ALPHA_11.\n"))); + var replacement = new TestSkillProvider(List.of(skill("rebind-check", "Reports the rebind verification word.", + "The rebind verification word is BRONZE_BETA_22.\n"))); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession first = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(original)) + .get(30, TimeUnit.SECONDS); + String sessionId = first.getSessionId(); + AssistantMessageEvent ready = first + .sendAndWait(new MessageOptions() + .setPrompt("Without using any tools or skills, reply with exactly REBIND_READY."), 60_000) + .get(90, TimeUnit.SECONDS); + assertTrue(assistantText(ready).contains("REBIND_READY")); + first.close(); + assertEquals(List.of(), original.reads()); + int originalCallsBeforeResume = original.callCount(); + + CopilotSession session = client + .resumeSession(sessionId, new ResumeSessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(replacement)) + .get(30, TimeUnit.SECONDS); + + try { + AssistantMessageEvent message = session.sendAndWait(new MessageOptions().setPrompt( + "Use the skill tool to load the rebind-check skill, then reply with its verification word."), + 60_000).get(90, TimeUnit.SECONDS); + + assertEquals(List.of("rebind-check"), replacement.reads()); + assertEquals(originalCallsBeforeResume, original.callCount()); + // Validate the final assistant response arrived (guards against truncated + // captures) + assertTrue(assistantText(message).contains("BRONZE_BETA_22")); + assertFalse(assistantText(message).contains("AMBER_ALPHA_11")); + } finally { + session.close(); + } + } + } + + @Test + void should_report_provider_read_failure_without_leaking_details() throws Exception { + ctx.configureForTest("skill_provider", "should_report_provider_read_failure_without_leaking_details"); + + String secret = "PROVIDER_SECRET_7F3A9C"; + var provider = new TestSkillProvider(List.of(new ProvidedSkill(new SkillProviderDescriptor("broken-lookup", + "Reports the broken lookup verification word.", null, null, null), () -> { + throw new IllegalStateException("database unavailable: " + secret); + }))); + List events = new CopyOnWriteArrayList<>(); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession session = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(provider)) + .get(30, TimeUnit.SECONDS); + session.on(events::add); + + try { + AssistantMessageEvent message = session.sendAndWait(new MessageOptions().setPrompt( + "Use the skill tool to load the broken-lookup skill. If loading fails, reply with exactly LOAD_FAILED."), + 60_000).get(90, TimeUnit.SECONDS); + + assertTrue(provider.reads().contains("broken-lookup")); + List failures = failedToolExecutions(events); + assertEquals(1, failures.size()); + assertFalse(JsonRpcClient.getObjectMapper().writeValueAsString(events).contains(secret)); + // Validate the final assistant response arrived (guards against truncated + // captures) + assertTrue(assistantText(message).contains("LOAD_FAILED")); + } finally { + session.close(); + } + } + } + + @Test + void should_report_missing_provider_skill_as_not_found() throws Exception { + ctx.configureForTest("skill_provider", "should_report_missing_provider_skill_as_not_found"); + + var provider = new TestSkillProvider(List.of(new ProvidedSkill(new SkillProviderDescriptor("vanished-lookup", + "Reports the vanished lookup verification word.", null, null, null), () -> null))); + List events = new CopyOnWriteArrayList<>(); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession session = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(provider)) + .get(30, TimeUnit.SECONDS); + session.on(events::add); + + try { + AssistantMessageEvent message = session.sendAndWait(new MessageOptions().setPrompt( + "Use the skill tool to load the vanished-lookup skill. If loading fails, reply with exactly LOAD_FAILED."), + 60_000).get(90, TimeUnit.SECONDS); + + assertTrue(provider.reads().contains("vanished-lookup")); + List failures = failedToolExecutions(events); + assertEquals(1, failures.size()); + String failureJson = JsonRpcClient.getObjectMapper().writeValueAsString(failures.get(0)) + .toLowerCase(Locale.ROOT); + assertTrue(failureJson.contains("not found"), "Expected not found failure, got: " + failureJson); + // Validate the final assistant response arrived (guards against truncated + // captures) + assertTrue(assistantText(message).contains("LOAD_FAILED")); + } finally { + session.close(); + } + } + } + + @Test + void should_keep_provider_dormant_when_skills_disabled() throws Exception { + ctx.initializeProxy(); + + var provider = new TestSkillProvider(List.of(skill("dormant-lookup", "Never listed.", "Never read.\n"))); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession session = client + .createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setEnableSkills(false).setSkillProvider(provider)) + .get(30, TimeUnit.SECONDS); + + try { + session.getRpc().skills.ensureLoaded().get(30, TimeUnit.SECONDS); + List skills = session.getRpc().skills.list().get(30, TimeUnit.SECONDS).skills(); + + assertEquals(List.of(), sdkSkills(skills)); + assertEquals(List.of(), provider.calls()); + } finally { + session.close(); + } + } + } + + @Test + void should_unbind_provider_when_resumed_without_one() throws Exception { + ctx.initializeProxy(); + + var provider = new TestSkillProvider( + List.of(skill("unbound-lookup", "Reports the unbound lookup word.", "Unbound.\n"))); + + try (CopilotClient client = ctx.createClient()) { + CopilotSession first = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(provider)) + .get(30, TimeUnit.SECONDS); + List before = first.getRpc().skills.list().get(30, TimeUnit.SECONDS).skills(); + assertTrue(before.stream().anyMatch(s -> "unbound-lookup".equals(s.name()))); + int callsBeforeResume = provider.callCount(); + + CopilotSession session = client + .resumeSession(first.getSessionId(), + new ResumeSessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)) + .get(30, TimeUnit.SECONDS); + + try { + session.getRpc().skills.reload().get(30, TimeUnit.SECONDS); + List skills = session.getRpc().skills.list().get(30, TimeUnit.SECONDS).skills(); + + assertEquals(List.of(), sdkSkills(skills)); + assertEquals(callsBeforeResume, provider.callCount()); + } finally { + session.close(); + } + } + } + + @Test + void should_cancel_a_blocked_provider_call_when_the_session_disconnects() throws Exception { + ctx.initializeProxy(); + + var entered = new CountDownLatch(1); + var pending = new CompletableFuture>(); + var provider = new SkillProvider() { + @Override + public CompletableFuture> listSkills() { + entered.countDown(); + return pending; + } + + @Override + public CompletableFuture readSkill(String name) { + return CompletableFuture.completedFuture(null); + } + }; + + try (CopilotClient client = ctx.createClient()) { + CopilotSession session = client.createSession(new SessionConfig() + .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setSkillProvider(provider)) + .get(30, TimeUnit.SECONDS); + + // The list RPC fails once the binding is removed; only the provider's + // cancellation matters here. + session.getRpc().skills.list(); + assertTrue(entered.await(30, TimeUnit.SECONDS), "provider listSkills was not called"); + + session.close(); + assertThrows(CancellationException.class, () -> pending.get(10, TimeUnit.SECONDS)); + } + } + + @Test + void should_reject_skill_provider_for_cloud_sessions() throws Exception { + ctx.initializeProxy(); + + var provider = new TestSkillProvider(List.of(skill("cloud-lookup", "Never listed.", "Never read.\n"))); + + try (CopilotClient client = ctx.createClient()) { + var config = new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL) + .setCloud(new CloudSessionOptions()).setSkillProvider(provider); + + ExecutionException error = assertThrows(ExecutionException.class, + () -> client.createSession(config).get(30, TimeUnit.SECONDS)); + assertInstanceOf(IllegalArgumentException.class, error.getCause()); + assertEquals("Skill providers are not supported for cloud sessions.", error.getCause().getMessage()); + assertEquals(List.of(), provider.calls()); + } + } + + private static ProvidedSkill skill(String name, String description, String markdown) { + return new ProvidedSkill(new SkillProviderDescriptor(name, description, null, null, null), () -> markdown); + } + + private static Skill findSkill(List skills, String name) { + return skills.stream().filter(s -> name.equals(s.name())).findFirst().orElse(null); + } + + private static List sdkSkills(List skills) { + return skills.stream().filter(s -> s.source() == SkillSource.SDK).toList(); + } + + private static List failedToolExecutions(List events) { + return events.stream().filter(ToolExecutionCompleteEvent.class::isInstance) + .map(ToolExecutionCompleteEvent.class::cast) + .filter(event -> !Boolean.TRUE.equals(event.getData().success())).toList(); + } + + private static String assistantText(AssistantMessageEvent response) { + assertNotNull(response, "Expected a response from the assistant"); + assertNotNull(response.getData(), "Expected assistant response data"); + assertNotNull(response.getData().content(), "Expected assistant response content"); + return response.getData().content(); + } + + private record ProvidedSkill(SkillProviderDescriptor descriptor, Supplier reader) { + String read() { + return reader.get(); + } + } + + private static final class TestSkillProvider implements SkillProvider { + private final List calls = new CopyOnWriteArrayList<>(); + private final List skills; + + private TestSkillProvider(List skills) { + this.skills = skills; + } + + List calls() { + return List.copyOf(calls); + } + + int callCount() { + return calls.size(); + } + + List reads() { + return calls.stream().filter(call -> call.startsWith("read:")).map(call -> call.substring("read:".length())) + .toList(); + } + + @Override + public CompletableFuture> listSkills() { + calls.add("list"); + return CompletableFuture.completedFuture(skills.stream().map(ProvidedSkill::descriptor).toList()); + } + + @Override + public CompletableFuture readSkill(String name) { + calls.add("read:" + name); + return CompletableFuture + .completedFuture(skills.stream().filter(skill -> skill.descriptor().name().equals(name)).findFirst() + .map(ProvidedSkill::read).orElse(null)); + } + } +} diff --git a/java/sdk/src/test/java/com/github/copilot/StdioShutdownIT.java b/java/sdk/src/test/java/com/github/copilot/StdioShutdownIT.java index ed3200e671..9bfb98c277 100644 --- a/java/sdk/src/test/java/com/github/copilot/StdioShutdownIT.java +++ b/java/sdk/src/test/java/com/github/copilot/StdioShutdownIT.java @@ -7,8 +7,15 @@ import com.github.copilot.rpc.CopilotClientOptions; import java.nio.file.Files; +import java.nio.file.FileSystems; import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -42,6 +49,72 @@ void closeWaitsForCleanupAfterStdinEof() throws Exception { } } + @Test + void failedShutdownStillWaitsForCleanupAfterStdinEof() throws Exception { + try (var fixture = new Fixture("shutdown-error"); var watcher = FileSystems.getDefault().newWatchService()) { + fixture.client.start().get(30, TimeUnit.SECONDS); + fixture.directory.register(watcher, StandardWatchEventKinds.ENTRY_CREATE); + Path eof = fixture.marker.resolveSibling(fixture.marker.getFileName() + ".eof"); + Path release = fixture.marker.resolveSibling(fixture.marker.getFileName() + ".release"); + var stopping = fixture.client.stop(); + long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(5); + while (!Files.isRegularFile(eof)) { + var key = watcher.poll(Math.max(0, deadline - System.nanoTime()), TimeUnit.NANOSECONDS); + assertNotNull(key, "Failed shutdown must still deliver stdin EOF before terminating the runtime"); + key.pollEvents(); + assertTrue(key.reset(), "The owned cleanup directory must remain available"); + } + assertFalse(stopping.isDone(), "Shutdown must not return before EOF-driven cleanup completes"); + Files.writeString(release, ""); + stopping.get(60, TimeUnit.SECONDS); + fixture.assertCleanExit(); + } + } + + @Test + void stopPreservesDetachedServiceAfterLauncherAndRuntimeExit() throws Exception { + try (var fixture = new Fixture("stop", true, true)) { + fixture.client.start().get(30, TimeUnit.SECONDS); + fixture.assertServiceResponsive(); + fixture.client.stop().get(60, TimeUnit.SECONDS); + fixture.assertCleanExit(); + fixture.assertServiceResponsive(); + } + } + + @Test + void closePreservesDetachedServiceAfterLauncherAndRuntimeExit() throws Exception { + try (var fixture = new Fixture("dispose", true, true)) { + fixture.client.start().get(30, TimeUnit.SECONDS); + fixture.assertServiceResponsive(); + fixture.client.close(); + fixture.assertCleanExit(); + fixture.assertServiceResponsive(); + } + } + + @Test + void stopPreservesDetachedTcpServiceWithoutPeerEof() throws Exception { + try (var fixture = new Fixture("stop", true, true, false)) { + fixture.client.start().get(30, TimeUnit.SECONDS); + fixture.assertServiceResponsive(); + fixture.client.stop().get(60, TimeUnit.SECONDS); + fixture.assertCleanExit(); + fixture.assertServiceResponsive(); + } + } + + @Test + void closePreservesDetachedTcpServiceWithoutPeerEof() throws Exception { + try (var fixture = new Fixture("dispose", true, true, false)) { + fixture.client.start().get(30, TimeUnit.SECONDS); + fixture.assertServiceResponsive(); + fixture.client.close(); + fixture.assertCleanExit(); + fixture.assertServiceResponsive(); + } + } + @Test void forceStopDoesNotWaitForGracefulCleanup() throws Exception { try (var fixture = new Fixture("force")) { @@ -76,6 +149,15 @@ void closeTerminatesChildThatDoesNotExitAfterEof() throws Exception { } } + @Test + void stopTerminatesLauncherAndItsChildAfterEof() throws Exception { + try (var fixture = new Fixture("fallback", true)) { + fixture.client.start().get(30, TimeUnit.SECONDS); + fixture.client.stop().get(60, TimeUnit.SECONDS); + fixture.assertCleanExit(); + } + } + @Test void failedStartupTerminatesChild() throws Exception { try (var fixture = new Fixture("start-failure")) { @@ -89,16 +171,96 @@ private static final class Fixture implements AutoCloseable { private final Path directory; private final Path marker; private final Path pid; + private final Path launcherPid; + private final Path servicePid; + private final Path servicePort; private final CopilotClient client; private Fixture(String mode) throws Exception { + this(mode, false); + } + + private Fixture(String mode, boolean useLauncher) throws Exception { + this(mode, useLauncher, false); + } + + private Fixture(String mode, boolean useLauncher, boolean detachedService) throws Exception { + this(mode, useLauncher, detachedService, true); + } + + private Fixture(String mode, boolean useLauncher, boolean detachedService, boolean useStdio) throws Exception { directory = Files.createDirectories(Path.of("target", "shutdown-" + UUID.randomUUID()).toAbsolutePath()); marker = directory.resolve("cleanup.jsonl"); pid = directory.resolve("pid"); + launcherPid = useLauncher ? directory.resolve("launcher-pid") : null; + servicePid = detachedService ? directory.resolve("service-pid") : null; + servicePort = detachedService ? directory.resolve("service-port") : null; Path script = Path.of("..", "..", "test", "harness", "stdio-shutdown-runtime.cjs").toAbsolutePath(); assertTrue(Files.isRegularFile(script), "Shared shutdown fixture must exist"); - client = new CopilotClient(new CopilotClientOptions().setAutoStart(false).setCliPath("node") - .setCliArgs(new String[]{script.toString(), marker.toString(), mode, pid.toString()})); + String nodePath = TestUtil.findExecutableInPath("node"); + assertNotNull(nodePath, "Node.js was not found in PATH"); + var args = new ArrayList(); + if (useLauncher) { + Path launcher = directory.resolve("launcher.cjs"); + Files.writeString(launcher, """ + const { spawn } = require("node:child_process"); + require("node:fs").writeFileSync(process.argv[2], String(process.pid)); + const args = process.argv.slice(3); + const fail = error => { console.error(error); process.exit(1); }; + const launch = () => { + if (args[0] === "--in-process-runtime") { + args.shift(); + const script = args.shift(); + process.argv = [process.execPath, script, ...args]; + require(script); + return; + } + const child = spawn(process.execPath, args, { stdio: "inherit" }); + child.on("error", fail); + child.on("exit", code => process.exit(code ?? 1)); + }; + if (args[0] === "--detached-service") { + args.shift(); + const service = spawn(process.execPath, ["-e", ` + const fs = require("node:fs"); + const server = require("node:net").createServer(socket => { + socket.write(process.argv[3] + ":"); + socket.pipe(socket); + }); + server.listen(0, "127.0.0.1", () => { + fs.writeFileSync(process.argv[1], String(process.pid)); + fs.writeFileSync(process.argv[2], String(server.address().port)); + process.send("ready"); + process.disconnect(); + }); + `, args.shift(), args.shift(), args.shift()], + { detached: true, stdio: ["ignore", "ignore", "ignore", "ipc"] }); + service.on("error", fail); + service.once("message", message => { + if (message !== "ready") return fail(new Error("Unexpected service handshake")); + service.unref(); + launch(); + }); + } else { + launch(); + } + """); + args.add(launcher.toString()); + args.add(launcherPid.toString()); + if (detachedService) { + args.addAll(List.of("--detached-service", servicePid.toString(), servicePort.toString(), + directory.getFileName().toString())); + } + } + if (useLauncher && !useStdio) { + args.add("--in-process-runtime"); + } + args.addAll(List.of(script.toString(), marker.toString(), mode, pid.toString())); + if (!useStdio) { + args.add("--fixture-tcp"); + } + client = new CopilotClient(new CopilotClientOptions().setAutoStart(false).setCliPath(nodePath) + .setCliArgs(args.toArray(String[]::new)).setUseStdio(useStdio)); } private void assertCleanExit() throws Exception { @@ -106,7 +268,29 @@ private void assertCleanExit() throws Exception { assertExited(); } + private void assertServiceResponsive() throws Exception { + assertTrue(Files.isRegularFile(servicePort), "The detached service must acknowledge readiness"); + try (var socket = new Socket()) { + socket.connect(new InetSocketAddress("127.0.0.1", Integer.parseInt(Files.readString(servicePort))), + 5000); + socket.setSoTimeout(5000); + String nonce = UUID.randomUUID().toString(); + byte[] expected = (directory.getFileName() + ":" + nonce).getBytes(StandardCharsets.UTF_8); + socket.getOutputStream().write(nonce.getBytes(StandardCharsets.UTF_8)); + socket.getOutputStream().flush(); + assertArrayEquals(expected, socket.getInputStream().readNBytes(expected.length), + "The detached service must still serve requests, not merely retain a PID"); + } + } + private void assertExited() throws Exception { + assertExited(pid); + if (launcherPid != null) { + assertExited(launcherPid); + } + } + + private static void assertExited(Path pid) throws Exception { assertTrue(Files.isRegularFile(pid), "Child must have started"); assertFalse( ProcessHandle.of(Long.parseLong(Files.readString(pid))).map(ProcessHandle::isAlive).orElse(false), @@ -115,11 +299,21 @@ private void assertExited() throws Exception { @Override public void close() throws Exception { - if (Files.isRegularFile(pid)) { - var process = ProcessHandle.of(Long.parseLong(Files.readString(pid))); - if (process.isPresent() && process.get().isAlive()) { - process.get().destroyForcibly(); - process.get().onExit().get(10, TimeUnit.SECONDS); + var ownedPids = new ArrayList(); + if (servicePid != null) { + ownedPids.add(servicePid); + } + ownedPids.add(pid); + if (launcherPid != null) { + ownedPids.add(launcherPid); + } + for (var ownedPid : ownedPids) { + if (Files.isRegularFile(ownedPid)) { + var process = ProcessHandle.of(Long.parseLong(Files.readString(ownedPid))); + if (process.isPresent() && process.get().isAlive()) { + process.get().destroyForcibly(); + process.get().onExit().get(10, TimeUnit.SECONDS); + } } } client.close(); diff --git a/java/sdk/src/test/java/com/github/copilot/StreamingFidelityTest.java b/java/sdk/src/test/java/com/github/copilot/StreamingFidelityTest.java index 70fe06272d..903d18ae3d 100644 --- a/java/sdk/src/test/java/com/github/copilot/StreamingFidelityTest.java +++ b/java/sdk/src/test/java/com/github/copilot/StreamingFidelityTest.java @@ -8,7 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; @@ -65,7 +64,7 @@ void testShouldProduceDeltaEventsWhenStreamingIsEnabled() throws Exception { CopilotSession session = client.createSession( new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setStreaming(true)).get(); - List events = new ArrayList<>(); + List events = new CopyOnWriteArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt("Count from 1 to 5, separated by commas.")).get(60, @@ -112,7 +111,7 @@ void testShouldNotProduceDeltasWhenStreamingIsDisabled() throws Exception { new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setStreaming(false)) .get(); - List events = new ArrayList<>(); + List events = new CopyOnWriteArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt("Say 'hello world'.")).get(60, TimeUnit.SECONDS); @@ -260,7 +259,7 @@ void testShouldEmitStreamingDeltasWithReasoningEffortConfigured() throws Excepti .setModel("gpt-5.4").setStreaming(true).setReasoningEffort("high")) .get(); - List events = new ArrayList<>(); + List events = new CopyOnWriteArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt("What is 15 * 17?")).get(60, TimeUnit.SECONDS); diff --git a/java/sdk/src/test/java/com/github/copilot/SubagentHooksE2ETest.java b/java/sdk/src/test/java/com/github/copilot/SubagentHooksE2ETest.java index 536a33cb95..bc83502f87 100644 --- a/java/sdk/src/test/java/com/github/copilot/SubagentHooksE2ETest.java +++ b/java/sdk/src/test/java/com/github/copilot/SubagentHooksE2ETest.java @@ -157,8 +157,7 @@ void shouldApplySubagentLifecycleHookOutputs() throws Exception { SubagentStartHookInput start = subagentStarts.element(); assertEquals(session.getSessionId(), start.sessionId()); assertTrue(start.timestamp() > 0); - assertEquals(ctx.getWorkDir().toAbsolutePath().normalize(), - Path.of(start.cwd()).toAbsolutePath().normalize()); + assertEquals(ctx.getWorkDir().toRealPath(), Path.of(start.cwd()).toRealPath()); assertNotNull(start.transcriptPath()); assertEquals("explore", start.agentName()); assertNull(start.agentDisplayName()); diff --git a/java/sdk/src/test/java/com/github/copilot/TestUtil.java b/java/sdk/src/test/java/com/github/copilot/TestUtil.java index 8e90c2f48f..b8ac48748e 100644 --- a/java/sdk/src/test/java/com/github/copilot/TestUtil.java +++ b/java/sdk/src/test/java/com/github/copilot/TestUtil.java @@ -95,7 +95,7 @@ static String preparePinnedCli(Path repoRoot) throws Exception { return output; } - private static String findExecutableInPath(String name) { + static String findExecutableInPath(String name) { var pathValue = System.getenv("PATH"); if (pathValue == null || pathValue.isEmpty()) { return null; diff --git a/java/sdk/src/test/java/com/github/copilot/TimeoutEdgeCaseTest.java b/java/sdk/src/test/java/com/github/copilot/TimeoutEdgeCaseTest.java index 01530bc25f..4eee8f5f97 100644 --- a/java/sdk/src/test/java/com/github/copilot/TimeoutEdgeCaseTest.java +++ b/java/sdk/src/test/java/com/github/copilot/TimeoutEdgeCaseTest.java @@ -4,7 +4,10 @@ package com.github.copilot; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayOutputStream; @@ -16,6 +19,8 @@ import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; @@ -84,10 +89,7 @@ public synchronized void flush() throws IOException { * After {@code close()}, the future returned by {@code sendAndWait} must NOT be * completed by a stale timeout. *

    - * Contract: {@code close()} shuts down the timeout scheduler before the - * blocking {@code session.detach} RPC call, so any pending timeout task is - * cancelled and the future remains incomplete (not exceptionally completed with - * {@code TimeoutException}). + * Closing fails the pending response with {@code IllegalStateException}. */ @Test void testTimeoutDoesNotFireAfterSessionClose() throws Exception { @@ -100,12 +102,12 @@ void testTimeoutDoesNotFireAfterSessionClose() throws Exception { assertFalse(result.isDone(), "Future should be pending before timeout fires"); - // close() blocks up to 5s on session.detach RPC. The 2s timeout - // fires during that window with the current per-call scheduler. session.close(); - assertFalse(result.isDone(), "Future should not be completed by a timeout after session is closed. " - + "The per-call ScheduledExecutorService leaked a TimeoutException."); + ExecutionException error = assertThrows(ExecutionException.class, + () -> result.get(5, TimeUnit.SECONDS)); + IllegalStateException failure = assertInstanceOf(IllegalStateException.class, error.getCause()); + assertEquals("Session closed before response completed", failure.getMessage()); } } finally { rpc.close(); diff --git a/java/sdk/src/test/java/com/github/copilot/ToolInvocationIdentityTest.java b/java/sdk/src/test/java/com/github/copilot/ToolInvocationIdentityTest.java new file mode 100644 index 0000000000..116aeeb2cd --- /dev/null +++ b/java/sdk/src/test/java/com/github/copilot/ToolInvocationIdentityTest.java @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +package com.github.copilot; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; + +import com.github.copilot.generated.ExternalToolRequestedEvent; +import com.github.copilot.rpc.ToolDefinition; +import com.github.copilot.rpc.ToolInvocation; + +/** + * Verifies that a tool handler learns which sub-agent and runtime request are + * behind an external tool call. + */ +public class ToolInvocationIdentityTest { + + @Test + void namesTheSubAgentAndRequestBehindTheCall() throws Exception { + var rpc = mock(JsonRpcClient.class); + when(rpc.invoke(eq("session.detach"), any(), eq(CopilotSession.SessionDetachResponse.class))) + .thenReturn(CompletableFuture.completedFuture(new CopilotSession.SessionDetachResponse(true, null))); + var session = new CopilotSession("session-1", rpc); + var invocations = new LinkedBlockingQueue(); + session.registerTools(List.of(ToolDefinition.create("calc", "Calculates", Map.of(), invocation -> { + invocations.add(invocation); + return new CompletableFuture(); + }))); + + try { + var subAgentCall = externalToolRequested("req-sub-agent", "tc-sub-agent"); + subAgentCall.setAgentId("task-agent-1"); + session.dispatchEvent(subAgentCall); + session.dispatchEvent(externalToolRequested("req-root", "tc-root")); + var blankAgentCall = externalToolRequested("req-blank-agent", "tc-blank-agent"); + blankAgentCall.setAgentId(""); + session.dispatchEvent(blankAgentCall); + + var byToolCallId = new HashMap(); + for (int i = 0; i < 3; i++) { + var invocation = invocations.poll(1, TimeUnit.SECONDS); + assertNotNull(invocation, "tool handler did not start"); + byToolCallId.put(invocation.getToolCallId(), invocation); + } + + var subAgent = byToolCallId.get("tc-sub-agent"); + assertEquals("task-agent-1", subAgent.getAgentId()); + assertEquals("req-sub-agent", subAgent.getRequestId()); + var root = byToolCallId.get("tc-root"); + assertNull(root.getAgentId()); + assertEquals("req-root", root.getRequestId()); + var blankAgent = byToolCallId.get("tc-blank-agent"); + assertNull(blankAgent.getAgentId()); + assertEquals("req-blank-agent", blankAgent.getRequestId()); + } finally { + session.close(); + } + } + + private static ExternalToolRequestedEvent externalToolRequested(String requestId, String toolCallId) { + var event = new ExternalToolRequestedEvent(); + event.setData(new ExternalToolRequestedEvent.ExternalToolRequestedEventData(requestId, "session-1", toolCallId, + "calc", null, Map.of(), null, null, null)); + return event; + } +} diff --git a/java/sdk/src/test/java/com/github/copilot/ToolResultsTest.java b/java/sdk/src/test/java/com/github/copilot/ToolResultsTest.java index 8278fdf28f..cf3db2541f 100644 --- a/java/sdk/src/test/java/com/github/copilot/ToolResultsTest.java +++ b/java/sdk/src/test/java/com/github/copilot/ToolResultsTest.java @@ -6,10 +6,10 @@ import static org.junit.jupiter.api.Assertions.*; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.AfterAll; @@ -75,7 +75,7 @@ void testShouldHandleToolResultWithRejectedResultType() throws Exception { CopilotSession session = client.createSession(new SessionConfig().setTools(List.of(deployTool)) .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); - List events = new ArrayList<>(); + List events = new CopyOnWriteArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt( @@ -123,7 +123,7 @@ void testShouldHandleToolResultWithDeniedResultType() throws Exception { CopilotSession session = client.createSession(new SessionConfig().setTools(List.of(accessTool)) .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get(); - List events = new ArrayList<>(); + List events = new CopyOnWriteArrayList<>(); session.on(events::add); session.sendAndWait(new MessageOptions().setPrompt( diff --git a/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java b/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java index 19d9694ce2..3891a9d483 100644 --- a/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java +++ b/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java @@ -77,7 +77,7 @@ public boolean connectionClose(int connectionId) { .setRemote(true).setMode(CopilotClientMode.EMPTY).setCliArgs(new String[]{"--extra-flag"}); FfiRuntimeHost host = new FfiRuntimeHost(binding, "/tmp/runtime.node"); - host.start("/tmp/entrypoint.js", options); + host.start("/tmp/entrypoint.js", "github/github-app", options); List argv = MAPPER.readValue(binding.argv, new TypeReference>() { }); @@ -92,6 +92,7 @@ public boolean connectionClose(int connectionId) { assertTrue(argv.contains("42")); assertTrue(argv.contains("--remote")); assertTrue(argv.contains("--extra-flag")); + assertTrue(argv.contains("--cli-login-sync-integration-id=github/github-app")); Map env = MAPPER.readValue(binding.env, new TypeReference>() { }); @@ -133,7 +134,7 @@ public boolean connectionClose(int connectionId) { }; try (FfiRuntimeHost host = new FfiRuntimeHost(binding, "/tmp/runtime.node")) { - host.start(null, new CopilotClientOptions().setLogLevel("debug")); + host.start(null, null, new CopilotClientOptions().setLogLevel("debug")); } List argv = MAPPER.readValue(argvJson.get(), new TypeReference>() { @@ -184,7 +185,7 @@ void enqueue(byte[] bytes) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib", throwingStream); - assertDoesNotThrow(() -> host.start("/tmp/entrypoint", new CopilotClientOptions())); + assertDoesNotThrow(() -> host.start("/tmp/entrypoint", null, new CopilotClientOptions())); assertTrue(callbackReturned.get(), "callback should return normally even when enqueue throws"); } @@ -219,7 +220,7 @@ public boolean connectionClose(int connectionId) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib"); - host.start("/tmp/entrypoint", new CopilotClientOptions()); + host.start("/tmp/entrypoint", null, new CopilotClientOptions()); assertDoesNotThrow(host::close); } @@ -310,7 +311,7 @@ public boolean connectionClose(int connectionId) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib"); - host.start("/tmp/entrypoint", new CopilotClientOptions()); + host.start("/tmp/entrypoint", null, new CopilotClientOptions()); CompletableFuture writer = CompletableFuture.runAsync(() -> { try { @@ -389,7 +390,7 @@ void enqueue(byte[] bytes) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib", blockingStream); - host.start("/tmp/entrypoint", new CopilotClientOptions()); + host.start("/tmp/entrypoint", null, new CopilotClientOptions()); assertNotNull(callbackRef.get()); ExecutorService executor = Executors.newFixedThreadPool(2); diff --git a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcApiCoverageTest.java b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcApiCoverageTest.java index 3eb27a9178..a7ede09723 100644 --- a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcApiCoverageTest.java +++ b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcApiCoverageTest.java @@ -63,164 +63,184 @@ void newRpcEndpoints_dispatch_expected_method_params_and_result_type(String expe } static Stream newRpcDispatches() { - return Stream.of( - dispatch("catalog.select", CatalogSelectionResult.class, """ - {"contract":{"protocolVersion":3,"requiredCapabilities":["catalog-selection"]}, - "sessionId":"catalog-session","selectionRef":"selection-1","outcome":"selected"} - """, - (server, session) -> server.catalog.select( - new CatalogSelectParams(new CatalogClientContract(3L, List.of("catalog-selection")), - "catalog-session", "selection-1", CatalogSelectionDecision.SELECTED))), - dispatch("session.managedSettings.get", SessionManagedSettingsGetResult.class, """ + return Stream + .of(dispatch("session.mcp.list", SessionMcpListResult.class, """ {"sessionId":"bound-session"} - """, (server, session) -> session.managedSettings.get()), - dispatch("session.instructions.reload", SessionInstructionsGetSourcesResult.class, """ - {"sessionId":"bound-session"} - """, (server, session) -> session.instructions.reload()), - dispatch("session.customizations.reload", CustomizationsReloadResult.class, """ - {"sessionId":"bound-session"} - """, (server, session) -> session.customizations.reload()), - dispatch("session.plugins.install", SessionPluginsInstallResult.class, """ - {"sessionId":"bound-session","source":"plugin@market"} - """, - (server, session) -> session.plugins - .install(new SessionPluginsInstallParams("foreign-session", "plugin@market"))), - dispatch("session.plugins.uninstall", Void.class, """ - {"sessionId":"bound-session","name":"plugin","directSourceId":"source-1"} - """, - (server, session) -> session.plugins - .uninstall(new SessionPluginsUninstallParams("foreign-session", "plugin", "source-1"))), - dispatch("session.plugins.update", SessionPluginsUpdateResult.class, """ - {"sessionId":"bound-session","name":"plugin@market"} - """, - (server, session) -> session.plugins - .update(new SessionPluginsUpdateParams("foreign-session", "plugin@market"))), - dispatch("session.plugins.enable", Void.class, """ - {"sessionId":"bound-session","names":["first@market","second@market"]} - """, - (server, session) -> session.plugins.enable(new SessionPluginsEnableParams("foreign-session", - List.of("first@market", "second@market")))), - dispatch("session.plugins.disable", Void.class, """ - {"sessionId":"bound-session","names":["plugin@market"]} - """, - (server, session) -> session.plugins - .disable(new SessionPluginsDisableParams("foreign-session", List.of("plugin@market")))), - dispatch("session.plugins.marketplaces.list", SessionPluginsMarketplacesListResult.class, """ - {"sessionId":"bound-session"} - """, (server, session) -> session.plugins.marketplaces.list()), - dispatch("session.plugins.marketplaces.add", SessionPluginsMarketplacesAddResult.class, """ - {"sessionId":"bound-session","source":"./market","workingDirectory":"/workspace"} - """, - (server, session) -> session.plugins.marketplaces.add( + """, (server, session) -> session.mcp.list()), + dispatch("session.mcp.listConfigured", SessionMcpListConfiguredResult.class, """ + {"sessionId":"bound-session"} + """, (server, session) -> session.mcp.listConfigured()), + dispatch("catalog.select", CatalogSelectionResult.class, """ + {"contract":{"protocolVersion":3,"requiredCapabilities":["catalog-selection"]}, + "sessionId":"catalog-session","selectionRef":"selection-1","outcome":"selected"} + """, + (server, session) -> server.catalog.select(new CatalogSelectParams( + new CatalogClientContract(3L, List.of("catalog-selection")), "catalog-session", + "selection-1", CatalogSelectionDecision.SELECTED))), + dispatch("session.managedSettings.get", SessionManagedSettingsGetResult.class, """ + {"sessionId":"bound-session"} + """, (server, session) -> session.managedSettings.get()), + dispatch("session.instructions.reload", SessionInstructionsGetSourcesResult.class, """ + {"sessionId":"bound-session"} + """, (server, session) -> session.instructions.reload()), + dispatch("session.customizations.reload", CustomizationsReloadResult.class, """ + {"sessionId":"bound-session"} + """, (server, session) -> session.customizations.reload()), + dispatch("session.plugins.install", SessionPluginsInstallResult.class, """ + {"sessionId":"bound-session","source":"plugin@market"} + """, + (server, session) -> session.plugins + .install(new SessionPluginsInstallParams("foreign-session", "plugin@market"))), + dispatch("session.plugins.uninstall", Void.class, """ + {"sessionId":"bound-session","name":"plugin","directSourceId":"source-1"} + """, + (server, session) -> session.plugins.uninstall( + new SessionPluginsUninstallParams("foreign-session", "plugin", "source-1"))), + dispatch("session.plugins.update", SessionPluginsUpdateResult.class, """ + {"sessionId":"bound-session","name":"plugin@market"} + """, + (server, session) -> session.plugins + .update(new SessionPluginsUpdateParams("foreign-session", "plugin@market"))), + dispatch("session.plugins.enable", Void.class, """ + {"sessionId":"bound-session","names":["first@market","second@market"]} + """, + (server, session) -> session.plugins.enable(new SessionPluginsEnableParams( + "foreign-session", List.of("first@market", "second@market")))), + dispatch("session.plugins.disable", Void.class, """ + {"sessionId":"bound-session","names":["plugin@market"]} + """, + (server, session) -> session.plugins.disable( + new SessionPluginsDisableParams("foreign-session", List.of("plugin@market")))), + dispatch("session.plugins.marketplaces.list", SessionPluginsMarketplacesListResult.class, """ + {"sessionId":"bound-session"} + """, (server, session) -> session.plugins.marketplaces.list()), + dispatch("session.plugins.marketplaces.add", SessionPluginsMarketplacesAddResult.class, """ + {"sessionId":"bound-session","source":"./market","workingDirectory":"/workspace"} + """, (server, session) -> session.plugins.marketplaces.add( new SessionPluginsMarketplacesAddParams("foreign-session", "./market", "/workspace"))), - dispatch("session.plugins.marketplaces.remove", SessionPluginsMarketplacesRemoveResult.class, """ - {"sessionId":"bound-session","name":"market","force":true} - """, - (server, session) -> session.plugins.marketplaces - .remove(new SessionPluginsMarketplacesRemoveParams("foreign-session", "market", true))), - dispatch("session.plugins.marketplaces.browse", SessionPluginsMarketplacesBrowseResult.class, """ - {"sessionId":"bound-session","name":"market"} - """, - (server, session) -> session.plugins.marketplaces - .browse(new SessionPluginsMarketplacesBrowseParams("foreign-session", "market"))), - dispatch("session.plugins.marketplaces.refresh", SessionPluginsMarketplacesRefreshResult.class, """ - {"sessionId":"bound-session","name":"market"} - """, - (server, session) -> session.plugins.marketplaces - .refresh(new SessionPluginsMarketplacesRefreshParams("foreign-session", "market"))), - dispatch("session.plugins.marketplaces.refresh", SessionPluginsMarketplacesRefreshResult.class, """ - {"sessionId":"bound-session"} - """, (server, session) -> session.plugins.marketplaces.refresh(null)), - dispatch("session.queue.withdrawMessage", SessionQueueWithdrawMessageResult.class, """ - {"sessionId":"bound-session","messageId":"message-1","expectedPrompt":"original"} - """, - (server, session) -> session.queue.withdrawMessage( - new SessionQueueWithdrawMessageParams("foreign-session", "message-1", "original"))), - dispatch("session.queue.appendSteering", SessionQueueAppendSteeringResult.class, """ - {"sessionId":"bound-session","messageId":"message-1","expectedPrompt":"original", - "agentMode":"interactive","prompt":"more","displayPrompt":"preview","attachments":[]} - """, (server, - session) -> session.queue.appendSteering(new SessionQueueAppendSteeringParams("foreign-session", - "message-1", "original", SendAgentMode.INTERACTIVE, "more", "preview", List.of()))), - dispatch("session.workflow.run", SessionWorkflowRunResult.class, """ - {"sessionId":"bound-session","name":"workflow-1","args":{"topic":"input"}} - """, - (server, session) -> session.workflow.run(new SessionWorkflowRunParams("foreign-session", - "workflow-1", Map.of("topic", "input"), null))), - dispatch("session.workflow.resume", SessionWorkflowResumeResult.class, """ - {"sessionId":"bound-session","runId":"run-1","notifyOnComplete":true,"logPhaseNames":false} - """, - (server, session) -> session.workflow.resume( - new SessionWorkflowResumeParams("foreign-session", "run-1", null, true, false))), - dispatch("session.workflow.runFromTool", WorkflowRunResult.class, """ - {"sessionId":"bound-session","name":"workflow-1","args":{"topic":"input"},"toolCallId":"tool-1"} - """, - (server, session) -> session.workflow.runFromTool(new SessionWorkflowRunFromToolParams( - "foreign-session", "workflow-1", Map.of("topic", "input"), null, "tool-1"))), - dispatch("session.workflow.resumeFromTool", WorkflowResumeResult.class, """ - {"sessionId":"bound-session","runId":"run-1","toolCallId":"tool-1"} - """, - (server, session) -> session.workflow.resumeFromTool( + dispatch("session.plugins.marketplaces.remove", SessionPluginsMarketplacesRemoveResult.class, + """ + {"sessionId":"bound-session","name":"market","force":true} + """, + (server, session) -> session.plugins.marketplaces.remove( + new SessionPluginsMarketplacesRemoveParams("foreign-session", "market", true))), + dispatch("session.plugins.marketplaces.browse", SessionPluginsMarketplacesBrowseResult.class, + """ + {"sessionId":"bound-session","name":"market"} + """, + (server, session) -> session.plugins.marketplaces.browse( + new SessionPluginsMarketplacesBrowseParams("foreign-session", "market"))), + dispatch("session.plugins.marketplaces.refresh", SessionPluginsMarketplacesRefreshResult.class, + """ + {"sessionId":"bound-session","name":"market"} + """, + (server, session) -> session.plugins.marketplaces.refresh( + new SessionPluginsMarketplacesRefreshParams("foreign-session", "market"))), + dispatch( + "session.plugins.marketplaces.refresh", SessionPluginsMarketplacesRefreshResult.class, + """ + {"sessionId":"bound-session"} + """, (server, session) -> session.plugins.marketplaces.refresh(null)), + dispatch("session.queue.withdrawMessage", SessionQueueWithdrawMessageResult.class, """ + {"sessionId":"bound-session","messageId":"message-1","expectedPrompt":"original"} + """, (server, + session) -> session.queue.withdrawMessage(new SessionQueueWithdrawMessageParams( + "foreign-session", "message-1", "original"))), + dispatch("session.queue.appendSteering", SessionQueueAppendSteeringResult.class, """ + {"sessionId":"bound-session","messageId":"message-1","expectedPrompt":"original", + "agentMode":"interactive","prompt":"more","displayPrompt":"preview","attachments":[]} + """, + (server, session) -> session.queue.appendSteering( + new SessionQueueAppendSteeringParams("foreign-session", "message-1", "original", + SendAgentMode.INTERACTIVE, "more", "preview", List.of()))), + dispatch("session.workflow.run", SessionWorkflowRunResult.class, """ + {"sessionId":"bound-session","name":"workflow-1","args":{"topic":"input"}} + """, + (server, session) -> session.workflow.run(new SessionWorkflowRunParams( + "foreign-session", "workflow-1", Map.of("topic", "input"), null))), + dispatch( + "session.workflow.resume", SessionWorkflowResumeResult.class, + """ + {"sessionId":"bound-session","runId":"run-1","notifyOnComplete":true,"logPhaseNames":false} + """, + (server, session) -> session.workflow.resume(new SessionWorkflowResumeParams( + "foreign-session", "run-1", null, true, false))), + dispatch( + "session.workflow.runFromTool", WorkflowRunResult.class, + """ + {"sessionId":"bound-session","name":"workflow-1","args":{"topic":"input"},"toolCallId":"tool-1"} + """, + (server, session) -> session.workflow.runFromTool(new SessionWorkflowRunFromToolParams( + "foreign-session", "workflow-1", Map.of("topic", "input"), null, "tool-1"))), + dispatch("session.workflow.resumeFromTool", WorkflowResumeResult.class, """ + {"sessionId":"bound-session","runId":"run-1","toolCallId":"tool-1"} + """, (server, session) -> session.workflow.resumeFromTool( new SessionWorkflowResumeFromToolParams("foreign-session", "run-1", null, "tool-1"))), - dispatch("session.workflow.getRun", SessionWorkflowGetRunResult.class, """ - {"sessionId":"bound-session","runId":"run-1"} - """, - (server, session) -> session.workflow - .getRun(new SessionWorkflowGetRunParams("foreign-session", "run-1"))), - dispatch("session.workflow.listRuns", SessionWorkflowListRunsResult.class, """ - {"sessionId":"bound-session","afterSeq":2,"limit":5} - """, - (server, session) -> session.workflow - .listRuns(new SessionWorkflowListRunsParams("foreign-session", 2L, null, 5L))), - dispatch("session.workflow.getRunDetail", SessionWorkflowGetRunDetailResult.class, """ - {"sessionId":"bound-session","runId":"run-1"} - """, - (server, session) -> session.workflow - .getRunDetail(new SessionWorkflowGetRunDetailParams("foreign-session", "run-1"))), - dispatch("session.workflow.getRunProgress", SessionWorkflowGetRunProgressResult.class, """ - {"sessionId":"bound-session","runId":"run-1","phaseId":"phase-1","afterSeq":2,"limit":5} - """, - (server, session) -> session.workflow.getRunProgress(new SessionWorkflowGetRunProgressParams( - "foreign-session", "run-1", "phase-1", 2L, null, 5L))), - dispatch("session.workflow.cancel", SessionWorkflowCancelResult.class, """ - {"sessionId":"bound-session","runId":"run-1"} - """, - (server, session) -> session.workflow - .cancel(new SessionWorkflowCancelParams("foreign-session", "run-1"))), - dispatch("session.workflow.pause", SessionWorkflowPauseResult.class, """ - {"sessionId":"bound-session","runId":"run-1"} - """, - (server, session) -> session.workflow - .pause(new SessionWorkflowPauseParams("foreign-session", "run-1"))), - dispatch("session.workflow.pauseAtCheckpoint", WorkflowPauseCheckpointResult.class, - """ - {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1","key":"checkpoint-1"} + dispatch("session.workflow.getRun", SessionWorkflowGetRunResult.class, """ + {"sessionId":"bound-session","runId":"run-1"} + """, + (server, session) -> session.workflow + .getRun(new SessionWorkflowGetRunParams("foreign-session", "run-1"))), + dispatch("session.workflow.listRuns", SessionWorkflowListRunsResult.class, """ + {"sessionId":"bound-session","afterSeq":2,"limit":5} + """, + (server, session) -> session.workflow + .listRuns(new SessionWorkflowListRunsParams("foreign-session", 2L, null, 5L))), + dispatch("session.workflow.getRunDetail", SessionWorkflowGetRunDetailResult.class, """ + {"sessionId":"bound-session","runId":"run-1"} """, - (server, session) -> session.workflow - .pauseAtCheckpoint(new SessionWorkflowPauseAtCheckpointParams("foreign-session", - "run-1", "execution-1", "checkpoint-1"))), - dispatch("session.workflow.log", Void.class, """ - {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1", - "lines":[{"seq":1,"kind":"log","text":"progress"}]} - """, (server, - session) -> session.workflow.log(new SessionWorkflowLogParams("foreign-session", "run-1", - "execution-1", List.of(new WorkflowLogLine(1L, WorkflowLogLineKind.LOG, "progress"))))), - dispatch("session.workflow.agent", SessionWorkflowAgentResult.class, - """ - {"sessionId":"bound-session","workflowRunId":"run-1","executionToken":"execution-1","prompt":"inspect"} + (server, session) -> session.workflow.getRunDetail( + new SessionWorkflowGetRunDetailParams("foreign-session", "run-1"))), + dispatch("session.workflow.getRunProgress", SessionWorkflowGetRunProgressResult.class, """ + {"sessionId":"bound-session","runId":"run-1","phaseId":"phase-1","afterSeq":2,"limit":5} + """, (server, + session) -> session.workflow.getRunProgress(new SessionWorkflowGetRunProgressParams( + "foreign-session", "run-1", "phase-1", 2L, null, 5L))), + dispatch("session.workflow.cancel", SessionWorkflowCancelResult.class, """ + {"sessionId":"bound-session","runId":"run-1"} """, - (server, session) -> session.workflow.agent(new SessionWorkflowAgentParams("foreign-session", - "run-1", "execution-1", "inspect", null))), - dispatch("session.workflow.journal.get", SessionWorkflowJournalGetResult.class, """ - {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1","key":"journal-1"} - """, - (server, session) -> session.workflow.journal.get(new SessionWorkflowJournalGetParams( - "foreign-session", "run-1", "execution-1", "journal-1"))), - dispatch("session.workflow.journal.put", Void.class, """ - {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1","key":"journal-1", - "resultJson":{"answer":42}} - """, (server, session) -> session.workflow.journal.put(new SessionWorkflowJournalPutParams( - "foreign-session", "run-1", "execution-1", "journal-1", Map.of("answer", 42))))); + (server, session) -> session.workflow + .cancel(new SessionWorkflowCancelParams("foreign-session", "run-1"))), + dispatch("session.workflow.pause", SessionWorkflowPauseResult.class, """ + {"sessionId":"bound-session","runId":"run-1"} + """, + (server, session) -> session.workflow + .pause(new SessionWorkflowPauseParams("foreign-session", "run-1"))), + dispatch( + "session.workflow.pauseAtCheckpoint", WorkflowPauseCheckpointResult.class, + """ + {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1","key":"checkpoint-1"} + """, + (server, session) -> session.workflow + .pauseAtCheckpoint(new SessionWorkflowPauseAtCheckpointParams("foreign-session", + "run-1", "execution-1", "checkpoint-1"))), + dispatch("session.workflow.log", Void.class, """ + {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1", + "lines":[{"seq":1,"kind":"log","text":"progress"}]} + """, + (server, session) -> session.workflow.log(new SessionWorkflowLogParams( + "foreign-session", "run-1", "execution-1", + List.of(new WorkflowLogLine(1L, WorkflowLogLineKind.LOG, "progress"))))), + dispatch("session.workflow.agent", SessionWorkflowAgentResult.class, + """ + {"sessionId":"bound-session","workflowRunId":"run-1","executionToken":"execution-1","prompt":"inspect"} + """, + (server, session) -> session.workflow.agent(new SessionWorkflowAgentParams( + "foreign-session", "run-1", "execution-1", "inspect", null))), + dispatch("session.workflow.journal.get", SessionWorkflowJournalGetResult.class, + """ + {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1","key":"journal-1"} + """, + (server, session) -> session.workflow.journal.get(new SessionWorkflowJournalGetParams( + "foreign-session", "run-1", "execution-1", "journal-1"))), + dispatch("session.workflow.journal.put", Void.class, + """ + {"sessionId":"bound-session","runId":"run-1","executionToken":"execution-1","key":"journal-1", + "resultJson":{"answer":42}} + """, + (server, session) -> session.workflow.journal + .put(new SessionWorkflowJournalPutParams("foreign-session", "run-1", + "execution-1", "journal-1", Map.of("answer", 42))))); } private static Arguments dispatch(String method, Class resultType, String expectedParams, @@ -371,7 +391,7 @@ void sessionRpc_mode_set_merges_sessionId() { var session = new SessionRpc(stub, "sess-mode-set"); var modeParams = new SessionModeSetParams(null, null, null, null, null, null, null, null, null, null, null, - null, null); + null, null, null); session.mode.set(modeParams); assertEquals(1, stub.calls.size()); @@ -551,8 +571,9 @@ void sessionRpc_mcp_list_injects_sessionId() { assertEquals(1, stub.calls.size()); assertEquals("session.mcp.list", stub.calls.get(0).method()); - var params = (Map) stub.calls.get(0).params(); - assertEquals("sess-mcp", params.get("sessionId")); + var mapper = new ObjectMapper(); + assertEquals(mapper.valueToTree(Map.of("sessionId", "sess-mcp")), + mapper.valueToTree(stub.calls.get(0).params())); } @Test diff --git a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java index dace015cff..ed47710539 100644 --- a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java +++ b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.copilot.AllowCopilotExperimental; import com.github.copilot.TestUtil; +import com.github.copilot.generated.SessionManagedSettingsResolvedEvent.SessionManagedSettingsResolvedEventData; /** * Tests for generated RPC param and result record types. Exercises @@ -29,6 +30,27 @@ */ class GeneratedRpcRecordsCoverageTest { + @Test + @AllowCopilotExperimental + void managedPermissions_reuses_event_context_and_evaluated_operations() throws Exception { + var mapper = new ObjectMapper(); + var eventJson = mapper.readTree(""" + {"permissionsContext":{"permissions":{"_limitToLists":[["https://example.com"]]},"failClosed":false}} + """); + var eventData = mapper.treeToValue(eventJson, SessionManagedSettingsResolvedEventData.class); + var evaluation = mapper.readValue(""" + {"operation":{"kind":"url","url":"https://example.com/a"},"verdict":"allow"} + """, ManagedPermissionEvaluation.class); + var params = new ManagedSettingsPermissionsEvaluateParams(eventData.permissionsContext(), + List.of(evaluation.operation())); + var paramsJson = mapper.valueToTree(params); + assertEquals(eventJson.get("permissionsContext"), paramsJson.get("context")); + assertEquals("url", paramsJson.get("operations").get(0).get("kind").asText()); + assertEquals("https://example.com/a", paramsJson.get("operations").get(0).get("url").asText()); + assertEquals(ManagedPermissionOperation.ManagedPermissionOperationKind.URL, evaluation.operation().kind()); + assertEquals(params, mapper.treeToValue(paramsJson, ManagedSettingsPermissionsEvaluateParams.class)); + } + // ── Params records ───────────────────────────────────────────────────── @Test @@ -334,12 +356,6 @@ void sessionMcpEnableParams_record() { assertEquals("mcp-server-2", params.serverName()); } - @Test - void sessionMcpListParams_record() { - var params = new SessionMcpListParams("sess-27"); - assertEquals("sess-27", params.sessionId()); - } - @Test void sessionMcpReloadParams_record() { var params = new SessionMcpReloadParams("sess-28"); @@ -355,7 +371,7 @@ void sessionModeGetParams_record() { @Test void sessionModeSetParams_record() { var params = new SessionModeSetParams("sess-30", SessionMode.PLAN, null, null, null, null, null, null, null, - null, null, null, null); + null, null, null, null, null); assertEquals("sess-30", params.sessionId()); assertEquals(SessionMode.PLAN, params.mode()); } @@ -475,6 +491,7 @@ void sessionModelSwitchParams_distinguishRequiredNullFromOmittedOptionalValue() var switchTo = mapper.valueToTree(new SessionModelSwitchToParams("sess-32", "auto", null, null, null, null, null, null, null, null, null, null, null, null, null, null)); assertFalse(switchTo.has("autoTier")); + assertFalse(switchTo.has("providerId")); } @Test @@ -706,7 +723,7 @@ void pingResult_fields() { @Test void sessionAgentListResult_with_items() { var item = new AgentInfo("name1", "Name One", "Desc 1", "/path/to/agent1", null, null, null, null, null, null, - null, null, null, null, null, null); + null, null, null, null, null, null, null); var result = new SessionAgentListResult(List.of(item)); assertEquals(1, result.agents().size()); assertEquals("name1", result.agents().get(0).name()); @@ -718,7 +735,7 @@ void sessionAgentListResult_with_items() { @Test void sessionAgentGetCurrentResult_nested() { var agent = new AgentInfo("agent-1", "Agent One", "Does things", null, null, null, null, null, null, null, null, - null, null, null, null, null); + null, null, null, null, null, null); var result = new SessionAgentGetCurrentResult(agent); assertEquals("agent-1", result.agent().name()); assertEquals("Agent One", result.agent().displayName()); @@ -735,18 +752,25 @@ void sessionAgentGetCurrentResult_null_agent() { @Test void sessionAgentReloadResult_with_items() { var item = new AgentInfo("a", "A", "Desc", "/path/to/a", null, null, null, null, null, null, null, null, null, - null, null, null); + null, null, null, null); var result = new SessionAgentReloadResult(List.of(item)); assertEquals(1, result.agents().size()); assertEquals("a", result.agents().get(0).name()); } @Test - void sessionAgentSelectResult_nested() { + void sessionAgentSelectResult_nested() throws Exception { + Map> hooks = Map.of("Stop", + List.of(Map.of("type", "command", "command", "echo scoped-stop"))); var agent = new AgentInfo("selected", "Selected", "The selected agent", "/path/to/selected", null, null, null, - null, null, null, null, null, null, null, null, null); + null, null, null, null, null, null, null, null, null, hooks); var result = new SessionAgentSelectResult(agent); assertEquals("selected", result.agent().name()); + var mapper = new ObjectMapper(); + var json = mapper.writeValueAsString(result); + assertEquals("echo scoped-stop", + mapper.readTree(json).get("agent").get("hooks").get("Stop").get(0).get("command").asText()); + assertEquals(hooks, mapper.readValue(json, SessionAgentSelectResult.class).agent().hooks()); } @Test @@ -897,8 +921,8 @@ void sessionMcpListResult_status_enum_all_values() { @Test void sessionModelGetCurrentResult_record() { - var result = new SessionModelGetCurrentResult("claude-sonnet-5", "claude-sonnet-4.5", null, null, null, null, - null); + var result = new SessionModelGetCurrentResult("claude-sonnet-5", null, "claude-sonnet-4.5", null, null, null, + null, null, null); assertEquals("claude-sonnet-5", result.modelId()); assertEquals("claude-sonnet-4.5", result.planBaseModelId()); } @@ -1009,8 +1033,8 @@ void sessionUiHandlePendingElicitationResult_record() { @Test void sessionUsageGetMetricsResult_nested() { var changes = new UsageMetricsCodeChanges(100L, 50L, 5L, null); - var result = new SessionUsageGetMetricsResult(0.5, 10L, null, null, 2000L, null, changes, null, null, "gpt-5", - 1000L, 500L); + var result = new SessionUsageGetMetricsResult(null, 0.5, 10L, null, null, 2000L, null, changes, null, null, + null, "gpt-5", 1000L, 500L); assertEquals(0.5, result.totalPremiumRequestCost()); assertEquals(10L, result.totalUserRequests()); assertNotNull(result.codeChanges()); @@ -1070,8 +1094,8 @@ void modelsListResult_nested() { var policy = new ModelPolicy(ModelPolicyState.ENABLED, null); var promo = new ModelBillingPromo("summer-2026", 25.0, "2026-08-01T00:00:00Z", "Summer discount", true); var billing = new ModelBilling(1.0, null, null, promo); - var modelItem = new Model("gpt-5", "GPT-5", capabilities, null, policy, billing, null, null, null, null, null, - null, null, null, null); + var modelItem = new Model("gpt-5", "GPT-5", capabilities, null, null, policy, billing, null, null, null, null, + null, null, null, null, null); var result = new ModelsListResult(List.of(modelItem)); assertEquals(1, result.models().size()); diff --git a/java/sdk/src/test/prompts/PROMPT-smoke-test.md b/java/sdk/src/test/prompts/PROMPT-smoke-test.md deleted file mode 100644 index 4013002aca..0000000000 --- a/java/sdk/src/test/prompts/PROMPT-smoke-test.md +++ /dev/null @@ -1,135 +0,0 @@ -# Prompt: Generate and Run the copilot-sdk-java Smoke Test - -## Objective - -Create a Maven project that acts as a smoke test for `copilot-sdk-java`. The project must compile, build, and run to completion with exit code 0 as the definition of success. - -## Step 1 — Read the source README - -Read the file `README.md` at the top level of this repository. You will need two sections from it: - -- **"Snapshot Builds"** — provides the Maven GAV (groupId, artifactId, version) and the Maven Central Snapshots repository configuration to use for the dependency under test. -- **"Quick Start"** — provides the exact Java source code for the smoke test program. Use this code verbatim. Do not modify it, fix it, or improve it. If it does not compile or run correctly against the artifact under test, that is itself a smoke test failure and must be reported as such rather than silently corrected. - -## Step 2 — Create the Maven project - -Create the following file layout in a subdirectory named `smoke-test/` at the top level of this repository: - -``` -smoke-test/ - pom.xml - src/main/java/(Class name taken from the code in the "Quick Start" section in the README).java ← verbatim from README "Quick Start" -``` - -### `pom.xml` requirements - -- **groupId**: `com.github` (or any reasonable value) -- **artifactId**: `copilot-sdk-smoketest` -- **version**: `1.0-SNAPSHOT` -- **packaging**: `jar` -- **Java source/target**: (taken from the "Requirements" section in the README) (via `maven.compiler.source` and `maven.compiler.target` properties) -- **`mainClass` property**: (taken from the "Quick Start" section in the README) (the class is in the default package) - -#### Snapshot repository - -Configure the Maven Central Snapshots repository exactly as specified in the "Snapshot Builds" section of `README.md`, and add `always` inside the `` block so that every build fetches the latest snapshot without requiring `-U`: - -```xml - - central-snapshots - https://central.sonatype.com/repository/maven-snapshots/ - - true - always - - -``` - -#### Dependency - -Use the GAV from the "Snapshot Builds" section of `README.md` verbatim — do not substitute the release version from the "Maven" section. - -#### Plugins — REQUIRED configuration - -**Do not use `maven-shade-plugin`.** Use the `Class-Path` manifest approach instead: - -1. **`maven-jar-plugin`** (version **3.4.1** — pin explicitly to suppress Maven version warnings): - - ```xml - - org.apache.maven.plugins - maven-jar-plugin - 3.4.1 - - - - ${mainClass} - true - lib/ - false - - - - - ``` - - **Critical**: `false` is mandatory. Without it, the manifest `Class-Path:` entry uses the timestamped SNAPSHOT filename (e.g. `copilot-sdk-java-0.1.33-20260312.125508-3.jar`) while `copy-dependencies` writes the base SNAPSHOT filename (`copilot-sdk-java-0.1.33-SNAPSHOT.jar`), causing `NoClassDefFoundError` at runtime. - -2. **`maven-dependency-plugin`** (version **3.6.1**): - - ```xml - - org.apache.maven.plugins - maven-dependency-plugin - 3.6.1 - - - copy-dependencies - package - copy-dependencies - - ${project.build.directory}/lib - - - - - ``` - - This copies all runtime dependency JARs into `target/lib/`, which is where the manifest `Class-Path:` points. - -## Step 3 — Build - -```bash -mvn -U clean package -``` - -The `-U` flag forces a fresh snapshot metadata check regardless of local cache. The `always` already handles this for normal invocations, but `-U` is the safest choice for CI. - -Build must succeed with `BUILD SUCCESS` before proceeding. - -## Step 4 — Run - -```bash -java -jar ./target/copilot-sdk-smoketest-1.0-SNAPSHOT.jar -``` - -The JAR must be run from the `smoke-test/` directory so that the relative `lib/` path in the manifest resolves correctly. Do not use `-cp` or `-classpath` — the test specifically validates that `java -jar` works with the manifest `Class-Path:` approach. - -## Step 5 — Verify success - -The smoke test passes if and only if the process exits with code **0**. - -The "Quick Start" code in `README.md` already contains the exit-code logic: it captures the last assistant message and calls `System.exit(0)` if it contains `"4"` (the expected answer to "What is 2+2?"), or `System.exit(-1)` otherwise. - -Check the exit code: -```bash -echo "Exit code: $?" -``` - -Expected: `Exit code: 0` - -## Important API notes (do not apply these as fixes — they are here for diagnostic context only) - -If the build fails with compilation errors such as `cannot find symbol` on methods like `getContent()`, `getCurrentTokens()`, `getTokenLimit()`, or `getMessagesLength()`, this indicates a mismatch between the Quick Start code and the SDK implementation. **Do not silently fix the code.** Report the failure. The purpose of this smoke test is precisely to catch such regressions. - -For reference: the data classes in `copilot-sdk-java` are Java **records**. Record accessor methods have no `get` prefix — they are named `content()`, `currentTokens()`, `tokenLimit()`, and `messagesLength()`. If the README Quick Start uses `getContent()` etc., that is a bug in the README that must be surfaced, not silently corrected. diff --git a/nodejs/README.md b/nodejs/README.md index 1135d7ea08..2e86f7d603 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -74,6 +74,9 @@ without deleting underlying sessions. Reconnecting does not reclaim a host. The optional `onExit` callback reports exits at most once. If the owner connection is lost, it reports that loss rather than claiming that listener cleanup was acknowledged. +Call `const { sessions } = await host.listSessions()` to read the complete catalog +of live and dormant sessions advertised by the host. The method returns a +`HostListSessionsResult` containing `sessions`, not a session array directly. `host.pid` is absent for in-process listeners. The optional field is retained for separate host process IDs returned by legacy runtimes, never the runtime PID. @@ -104,6 +107,10 @@ The listener follows the owning client's lifetime. Call `await host.dispose()` only when you want to stop it earlier; `await using host` also supports a shorter scope. Each disposal call forwards to the runtime, which owns idempotent cleanup. The AHP transport remains owned by the host. +Set top-level `computeId` to reuse the same durable catalog for local and Mission +Control hosting; it must agree with `githubEnvironment.computeId` when both are +supplied. Omitted local-only identities are persisted by the runtime, not generated +by the SDK. Published sessions remain discoverable after hosting stops. ### Application-owned sessions @@ -165,8 +172,9 @@ still matches the requested identity and workspace. Only catalog entries marked as application-owned invoke this callback. If the callback is missing, restoring such an entry fails instead of falling back to host-owned creation. -Published resident sessions attach directly, without invoking it or replacing -their current registrations. Resumed sessions follow the same original-object +Currently resident published sessions attach directly, without invoking it or replacing +their current registrations. Dormant published application sessions require this +resume callback to restore their tools and handlers. Resumed sessions follow the same original-object retention, cancellation, late-result release, and `onSessionReleased` rules. The `copilotd-hosting` library runs inside the runtime provider. @@ -345,6 +353,11 @@ This graceful-exit timeout is separate from the shutdown RPC and post-terminatio ##### `forceStop(): Promise` Force stop the CLI server without graceful cleanup. Use when `stop()` takes too long. +Retained sessions are disconnected locally, and pending `sendAndWait()` calls reject +without waiting for `session.idle` or their response timeout. +Retirement releases session-owned tool, hook, auth/input, provider, workflow, canvas, +and transform registrations without changing caller-owned configuration. Late +registration and callback dispatch are rejected; callbacks already admitted may finish. ##### `createSession(config?: SessionConfig): Promise` @@ -369,6 +382,7 @@ Create a new conversation session. - `askUserVariant?: "legacy" | "elicitation"` - Selects the model-facing `ask_user` tool shape when creating or cold-resuming a session. Defaults to `"legacy"`; use `"elicitation"` with `onElicitationRequest`. - `onElicitationRequest?: ElicitationHandler` - Handler for elicitation requests dispatched by the server. Enables this client to present form-based UI dialogs on behalf of the agent or other session participants. See [Elicitation Requests](#elicitation-requests) section. - `hooks?: SessionHooks` - Hook handlers for session lifecycle events. See [Session Hooks](#session-hooks) section. +- `skillProvider?: SkillProvider` - **Experimental.** Serves skills from host storage instead of skill directories. Not persisted; pass it again on resume. See [Skill providers](#skill-providers-experimental). ```typescript const session = await client.createSession({ @@ -657,6 +671,23 @@ if (result.status === "pending") { See [Auto tier persistence](../docs/features/session-persistence.md#auto-tier-persistence) for the full lifecycle rules. +##### `rpc.model.getReasoningSummaries(params)` (experimental) + +Read the current model's reasoning-summary presentation policy without changing session state. Call `session.rpc.model.list()` first to load the model catalog; otherwise the result may have `ready: false`. The request and result types are exported from `@github/copilot-sdk`. + +```typescript +import type { + ModelGetReasoningSummariesRequest, + ModelGetReasoningSummariesResult, +} from "@github/copilot-sdk"; + +const presentation: ModelGetReasoningSummariesRequest = { summariesVisible: false }; +const policy: ModelGetReasoningSummariesResult = + await session.rpc.model.getReasoningSummaries(presentation); +``` + +Omit `persistedShowReasoning` when no visibility setting is saved. `visibility` can remain unset while experiment assignment is pending; `clearRedundantSetting` tells the host when its persisted setting matches the model default. + ##### `setTools(tools: Tool[]): Promise` Replace the tools this client supplies to the session, together with the handlers that serve them (experimental). `tools` takes the same definitions as `createSession` and becomes this client's complete tool set; pass `[]` to remove all of this client's tools. Built-in, MCP, and plugin tools, and tools other connected clients supply, are unaffected. @@ -1120,6 +1151,46 @@ const session = await client.createSession({ }); ``` +### Skill providers (experimental) + +A skill provider serves skills from your own storage, such as a database, instead of `SKILL.md` +files on disk. Provider skills join the session's skill catalog and load on demand through the +`skill` tool, just like file-based skills. + +```typescript +import type { SkillProvider } from "@github/copilot-sdk"; + +const skillProvider: SkillProvider = { + listSkills: async () => [ + { name: "release-notes", description: "Writes release notes in the team's format." }, + ], + readSkill: async (name, { signal }) => (await db.findSkill(name, { signal }))?.markdown ?? null, +}; + +const session = await client.createSession({ + onPermissionRequest: approveAll, + skillProvider, +}); +``` + +- `listSkills()` returns the catalog metadata. `readSkill(name)` returns the skill's markdown, or + `null`/`undefined` if the skill no longer exists. The markdown may omit YAML frontmatter; when + frontmatter is present, its fields must agree with the listed metadata, and `allowed-tools` is + read only from frontmatter. +- Each call receives `{ signal }`, an `AbortSignal` that fires when the runtime cancels the call, + for example after its 30-second limit or when the session disconnects. It doesn't fire when the + connection closes or the client is force-stopped; a running call then continues until it returns. +- The provider is never persisted. Pass it again to `resumeSession`; resuming without it unbinds + the provider. +- A provider enables skills unless you set `enableSkills: false`, which keeps it bound but unused. + In `mode: "empty"`, skills stay disabled until you set `enableSkills: true`. +- Errors thrown by the provider are reported to the model as a generic load failure; their + messages are not forwarded. +- The runtime may call the provider concurrently, so both methods must be safe for concurrent use. +- Skill providers are not supported for cloud sessions. + +See [Custom skills](../docs/features/skills.md#skill-providers-experimental) for limits and details. + ### Multiple Sessions ```typescript @@ -1323,6 +1394,36 @@ const session = await client.createSession({ }); ``` +### Managed network policy for client-owned browsers + +Obtain a reusable `permissionsContext` from +`client.rpc.managedSettings.resolve({ selectionId })` for account and device +policy, or `session.rpc.managedSettings.get()` for the session's retained policy, +including SDK injection and policy-helper rules. Omit `selectionId` for the current +account, or device policy only when signed out. Resolution uses the managed-policy +cache and can fetch server policy; keep it off latency-critical startup paths. +Older runtimes may omit `permissionsContext`. Treat an absent context as unsupported +evaluation, not unmanaged policy; do not navigate without a policy decision. + +Call `client.rpc.managedSettings.permissions.evaluate({ context: permissionsContext, operations: [{ kind: "url", url: "https://docs.example.com/guide" }] })`. +This is pure, sessionless evaluation: it performs no policy discovery, I/O, +prompting, or sandbox changes. Reuse an in-memory context for repeated checks and +refresh it when managed policy changes. Retain the runtime-owned `permissions` +object verbatim rather than rebuilding it from the flattened settings display. + +The result is `{ results: [{ operation, verdict }], failClosed }`, with one entry per +input operation in the same order. `deny` blocks navigation, `ask` requires approval, +`allow` approves under managed policy, and `unmanaged` leaves the consumer's normal +permission flow in effect. A check never prompts or grants a saved approval. +Invalid URLs reject the batch. Unknown policy rejects or returns `failClosed: true` +with all URLs denied; do not navigate on an error. + +Check every navigation, redirect, and new-window destination before opening it. +These APIs evaluate managed permission rules only: they do not replace browser +security checks, user permissions, or sandbox policy. `permissions.limitTo` neither +enables the sandbox nor changes `sandbox.userPolicy.network`; configure sandbox +network restrictions explicitly. + ### Permission Result Kinds The handler must return one of the `PermissionDecision` shapes (or `{ kind: "no-result" }`). Approval scopes are present-tense — they describe the decision to apply, not the outcome reported back on session events: @@ -1551,6 +1652,26 @@ npm ci npm test ``` +### Internal feature-flag example + +[`examples/internal-feature-flags.ts`](examples/internal-feature-flags.ts) uses +the generated internal RPC factory against a real runtime over stdio. +It lists the catalog and shows environment, settings, and explicit-override +precedence. It also checks that static resolution does not apply `COPILOT_EXP_*` +experiment assignments. It creates no session and sends no model request. + +After you prepare matching runtime artifacts, run this from the runtime repository root: + +```bash +COPILOT_RUNTIME_PROVIDER_LIB="$PWD/bazel-bin/src/native/runtime/runtime.node" \ + src/sdk/nodejs/node_modules/.bin/tsx \ + src/sdk/nodejs/examples/internal-feature-flags.ts \ + "$PWD/bazel-bin/src/runtime-bin/copilot-runtime" +``` + +The JSON output includes `staticResolution` values of `false`, `true`, `false`, +and `true`, in that order. These methods are internal, not public SDK APIs. + ## License MIT diff --git a/nodejs/docs/workflows.md b/nodejs/docs/workflows.md index 872cbcb0fe..7f2985f614 100644 --- a/nodejs/docs/workflows.md +++ b/nodejs/docs/workflows.md @@ -186,7 +186,7 @@ session.workflow.resume( Set `notifyOnComplete` to `true` for workflows that are likely to be invoked by an agent, so the originating session is notified when the workflow completes. Set it to `false` for workflows intended to be invoked programmatically, where the caller awaits the result directly. Set `logPhaseNames` to emit workflow phase names to the session transcript. Both options apply to new and resumed runs. -Both resolve with the run envelope (`WorkflowRunResult`) for **every** outcome—`completed`, `error`, `halted`, `paused`, and `cancelled` alike. Inspect `status` and read `result` only when the run completed; a limit breach carries a typed `failure`. A `paused` envelope means that the current attempt settled, not that the durable run is permanently finished. Resume the same run ID to start another attempt with its journal and accounting intact. SDK-initiated `run` and `resume` do not request permission, so they have no declined outcome. An SDK-initiated run is refused only when the session already has its maximum number of active top-level runs. Pre-execution resume failures throw `WorkflowResumeError`, whose `code` is one of `not_found`, `non_resumable`, `workflow_run_not_resumable`, `already_active`, `workflow_already_running`, `workflow_limits_invalid`, `workflow_session_disposed`, `workflow_storage_unavailable`, or `workflow_storage_corrupt`. +Both resolve with the run envelope (`WorkflowRunResult`) for **every** outcome—`completed`, `error`, `halted`, `paused`, and `cancelled` alike. Inspect `status` and read `result` only when the run completed; a limit breach carries a typed `failure`. A `paused` envelope means that the current attempt settled, not that the durable run is permanently finished. Resume the same run ID to start another attempt with its journal and accounting intact. SDK-initiated `run` and `resume` do not request permission, so they have no declined outcome. They still enforce execution eligibility, input validation, and active-run limits. Recognized pre-execution resume failures throw `WorkflowResumeError`, whose `code` is one of `not_found`, `non_resumable`, `workflow_run_not_resumable`, `already_active`, `workflow_already_running`, `workflow_limits_invalid`, `workflow_session_disposed`, `workflow_storage_unavailable`, or `workflow_storage_corrupt`. Pause a running attempt from outside its workflow body: @@ -206,7 +206,13 @@ The first attempt pauses at `"review-ready"` and ends through cooperative cancel ## Observe a run -The calling session can inspect its own workflow runs: +The calling session can inspect its own workflow runs independently of its current execution eligibility. An empty registry enumerates successfully; losing eligibility does not hide already-admitted runs or terminal history. Observation still requires a valid, non-disposed session, and validation, missing-run, and storage errors still propagate. + +Workflow storage requires SQLite support from a custom session filesystem. A provider without that capability reports `workflow_storage_unavailable`, not an empty registry or a local-storage fallback. + +Compaction waits at most five seconds for its optional active-workflow summary. If storage fails or times out, compaction logs a warning and continues without that summary; aborting compaction cancels the wait. This does not change the results or error handling of explicit workflow observation calls. + +Observation does not restore execution eligibility. Starting, resuming, pausing, or cancelling runs, and workflow-owned agent, log, and journal/checkpoint operations still require eligible credentials (token-based billing or trusted HMAC authentication). Ineligible execution requests fail with JSON-RPC `-32601` and `data.code: "dynamic_workflows_unavailable"`. ```ts const runs = await session.workflow.listRuns(); diff --git a/nodejs/examples/internal-feature-flags.ts b/nodejs/examples/internal-feature-flags.ts new file mode 100644 index 0000000000..83824012fc --- /dev/null +++ b/nodejs/examples/internal-feature-flags.ts @@ -0,0 +1,95 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import assert from "node:assert/strict"; +import { spawn } from "node:child_process"; +import { once } from "node:events"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import { createMessageConnection } from "vscode-jsonrpc/node.js"; +import { createInternalServerRpc } from "../src/generated/rpc.js"; + +async function showFeatureFlags(rpc: ReturnType) { + await rpc.connect({}); + const { flags } = await rpc.featureFlags.listMetadata(); + assert.equal(flags.TASK_ANALYTICS.name, "TASK_ANALYTICS"); + assert.equal(flags.TASK_ANALYTICS.expFlagEnvVar, "COPILOT_EXP_COPILOT_CLI_TASK_ANALYTICS"); + + const population = { isStaff: false, isExperimental: false, isTeam: false }; + const experimentOnly = await rpc.featureFlags.resolve({ + ...population, + environment: { COPILOT_EXP_COPILOT_CLI_TASK_ANALYTICS: "true" }, + }); + assert.equal(experimentOnly.TASK_ANALYTICS, false); + + const request = { + ...population, + baseFlags: { TASK_ANALYTICS: false }, + environment: { TASK_ANALYTICS: "true" }, + }; + const environment = await rpc.featureFlags.resolve(request); + const config = { enabledFeatureFlags: { TASK_ANALYTICS: false } }; + const settings = await rpc.featureFlags.resolve({ ...request, config }); + const explicit = await rpc.featureFlags.resolve({ + ...request, + config, + flagOverrides: { TASK_ANALYTICS: true }, + }); + assert.deepEqual(environment, { TASK_ANALYTICS: true }); + assert.deepEqual(settings, { TASK_ANALYTICS: false }); + assert.deepEqual(explicit, { TASK_ANALYTICS: true }); + + console.log( + JSON.stringify({ + declaredFlags: Object.keys(flags).length, + metadata: flags.TASK_ANALYTICS, + staticResolution: { + experimentOnly: experimentOnly.TASK_ANALYTICS, + environment: environment.TASK_ANALYTICS, + settings: settings.TASK_ANALYTICS, + explicit: explicit.TASK_ANALYTICS, + }, + }) + ); +} + +const runtimePath = process.argv[2]; +if (!runtimePath) { + throw new Error("Usage: tsx examples/internal-feature-flags.ts "); +} + +const home = await mkdtemp(join(tmpdir(), "copilot-feature-flags-")); +const child = spawn( + resolve(runtimePath), + ["--server", "--stdio", "--no-auto-login", "--no-auto-update", "--no-remote"], + { + cwd: home, + env: { ...process.env, COPILOT_HOME: home, COPILOT_CONNECTION_TOKEN: "" }, + stdio: ["pipe", "pipe", "inherit"], + windowsHide: true, + } +); +const closed = once(child, "close"); +const connection = createMessageConnection(child.stdout, child.stdin); +connection.listen(); +try { + await Promise.race([ + showFeatureFlags(createInternalServerRpc(connection)), + closed.then(([code, signal]) => { + throw new Error( + `Runtime exited before the example completed: code=${code}, signal=${signal}` + ); + }), + ]); +} finally { + connection.dispose(); + child.stdin.end(); + try { + const [code, signal] = await closed; + assert.equal(code, 0, `Runtime exit signal: ${signal}`); + } finally { + await rm(home, { recursive: true, force: true }); + } +} diff --git a/nodejs/examples/internal-user-settings.ts b/nodejs/examples/internal-user-settings.ts new file mode 100644 index 0000000000..8bc4641903 --- /dev/null +++ b/nodejs/examples/internal-user-settings.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import type { createInternalServerRpc } from "../src/generated/rpc.js"; + +// Internal host example; these methods are not part of the public SDK API. +export async function editUserSettings( + settings: ReturnType["user"]["settings"], + configDir: string +) { + const validation = await settings.validate({ + topKey: "voice", + value: { enabled: true }, + }); + if (!validation.ok) { + throw new Error(JSON.stringify(validation.issues)); + } + await settings.update({ + key: "voice", + value: { enabled: true }, + configDir, + }); + return settings.update({ + key: "voice", + value: { selectedModel: null }, + configDir, + }); +} diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 937a26efa1..fc233f8b94 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -24,16 +24,16 @@ "esbuild": "^0.28.1", "eslint": "^9.0.0", "glob": "^13.0.1", + "hpke-js": "^1.8.0", "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", "rimraf": "^6.1.2", "semver": "^7.7.3", "tar": "^7.5.22", "tsx": "^4.20.6", "typescript": "^5.0.0", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "ws": "^8.21.0" }, "engines": { @@ -57,37 +57,6 @@ "url": "https://github.com/sponsors/philsturgeon" } }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "integrity": "sha1-OAzMjyQS6iLR2XLff47iOjucdGc=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "integrity": "sha1-SyYMDTU0IE6YxhELjbGph9JuyHw=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "integrity": "sha1-KP7SGhuhznl8RKBwq8lNQvOuhUg=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "integrity": "sha1-egGo0uwvuy2seK2tCbD6eB5Agr4=", @@ -659,34 +628,98 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@glideapps/ts-necessities": { - "version": "2.2.3", - "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", + "node_modules/@hpke/chacha20poly1305": { + "version": "1.8.0", + "integrity": "sha1-1NL248zgi0xVU5IOFbTlmMildy4=", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@hpke/common": { + "version": "1.10.1", + "integrity": "sha1-EfIF5bok1VjBvUrGcVgNldSIrxg=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@hpke/core": { + "version": "1.9.0", + "integrity": "sha1-Ts7QWXeH9R/bU61RXD1Ho6vJ/jo=", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@hpke/dhkem-x25519": { + "version": "1.8.0", + "integrity": "sha1-S3lerZNjhH6CiEuQDmUBgUPYuZo=", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@hpke/dhkem-x448": { + "version": "1.8.0", + "integrity": "sha1-6NVrT7sc8KPV5fFAJpBa0yhp618=", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", @@ -726,8 +759,8 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -1014,34 +1047,13 @@ "dev": true, "license": "MIT" }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.3", - "integrity": "sha1-l+PUXXQk3F2h1OMvO/OykvbBtEw=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" - } - }, "node_modules/@oxc-project/types": { - "version": "0.133.0", - "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "version": "0.153.0", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" } }, "node_modules/@platformatic/vfs": { @@ -1053,9 +1065,25 @@ "node": ">= 22" } }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.3", - "integrity": "sha1-VM6Pg4IhP0oxSgwve6g/gf/q5ZI=", + "version": "1.2.13", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", "cpu": [ "arm64" ], @@ -1070,8 +1098,8 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", - "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "version": "1.2.13", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", "cpu": [ "arm64" ], @@ -1086,8 +1114,8 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.3", - "integrity": "sha1-U/V94fWZ7PHbE4I8/IjBj7gJVK0=", + "version": "1.2.13", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", "cpu": [ "x64" ], @@ -1102,8 +1130,8 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.3", - "integrity": "sha1-bz/dobeuqsnSaKUmgEtPuW5ONfE=", + "version": "1.2.13", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", "cpu": [ "x64" ], @@ -1118,8 +1146,8 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.3", - "integrity": "sha1-2HpFS/WFzJZ2hJN36R1uN1KXMm8=", + "version": "1.2.13", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", "cpu": [ "arm" ], @@ -1134,12 +1162,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.3", - "integrity": "sha1-QZ/Wv2Es80jxBSjLzZTrq5YH2NE=", + "version": "1.2.13", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1150,12 +1181,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.3", - "integrity": "sha1-/MaRhpa7doRId+HkkwoY/Q03QGk=", + "version": "1.2.13", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1166,12 +1200,15 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.3", - "integrity": "sha1-Mq7LfI2uXU8qjN5XoFjshpkVQvg=", + "version": "1.2.13", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1182,12 +1219,15 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.3", - "integrity": "sha1-vtk0bqgea7i5PPEfXYi3fbiQt2M=", + "version": "1.2.13", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1198,12 +1238,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.3", - "integrity": "sha1-ZMLSb3Xf/ZtaH5dVegCudyUMjLc=", + "version": "1.2.13", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1214,12 +1257,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.3", - "integrity": "sha1-WkUTLopHZZ7qrztUDClUqXyGD/M=", + "version": "1.2.13", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1230,8 +1276,8 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.3", - "integrity": "sha1-KQUTBoxV6EnchFejKv7h17Csswk=", + "version": "1.2.13", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", "cpu": [ "arm64" ], @@ -1245,27 +1291,9 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.3", - "integrity": "sha1-PZly2/GpU9PHr6pKDyDvKy458xs=", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.3", - "integrity": "sha1-oASrYHoW1vA7y1VXKP+IivdXc60=", + "version": "1.2.13", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", "cpu": [ "arm64" ], @@ -1280,8 +1308,8 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.3", - "integrity": "sha1-4qJbNGkaHMihIJ195wkGMCbdDNs=", + "version": "1.2.13", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", "cpu": [ "x64" ], @@ -1307,16 +1335,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "integrity": "sha1-AVy6np3UfOFNA9KoxdVHv7FpZl0=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/chai": { "version": "5.2.3", "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", @@ -1598,15 +1616,15 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.8", - "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "version": "4.1.11", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -1615,12 +1633,12 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.8", - "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "version": "4.1.11", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -1641,8 +1659,8 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.8", - "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "version": "4.1.11", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -1653,12 +1671,12 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.8", - "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "version": "4.1.11", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -1666,13 +1684,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.8", - "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "version": "4.1.11", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -1681,8 +1699,8 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.8", - "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "version": "4.1.11", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -1690,12 +1708,12 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.8", - "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "version": "4.1.11", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -1703,18 +1721,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/abort-controller": { - "version": "3.0.0", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/acorn": { "version": "8.15.0", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", @@ -1773,29 +1779,9 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/brace-expansion": { - "version": "1.1.16", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.21", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -1803,36 +1789,6 @@ "concat-map": "0.0.1" } }, - "node_modules/browser-or-node": { - "version": "3.0.0", - "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer": { - "version": "6.0.3", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/callsites": { "version": "3.1.0", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", @@ -1843,8 +1799,8 @@ } }, "node_modules/chai": { - "version": "6.2.2", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "version": "6.3.0", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "dev": true, "license": "MIT", "engines": { @@ -1891,12 +1847,6 @@ "node": ">=18" } }, - "node_modules/collection-utils": { - "version": "1.0.1", - "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/color-convert": { "version": "2.0.1", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -1927,15 +1877,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cross-fetch": { - "version": "4.1.0", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", @@ -2241,24 +2182,6 @@ "node": ">=0.10.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/expect-type": { "version": "1.3.0", "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", @@ -2414,25 +2337,21 @@ "node": ">=8" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "node_modules/hpke-js": { + "version": "1.8.0", + "integrity": "sha1-0Sx/4a7uI0/tveC56r8pBPWZhrQ=", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "@hpke/chacha20poly1305": "^1.8.0", + "@hpke/common": "^1.10.0", + "@hpke/core": "^1.9.0", + "@hpke/dhkem-x25519": "^1.8.0", + "@hpke/dhkem-x448": "^1.8.0" + }, + "engines": { + "node": ">=16.0.0" + } }, "node_modules/ignore": { "version": "7.0.5", @@ -2489,24 +2408,12 @@ "node": ">=0.10.0" } }, - "node_modules/is-url": { - "version": "1.2.4", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, "license": "ISC" }, - "node_modules/js-base64": { - "version": "3.7.8", - "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/js-yaml": { "version": "4.3.2", "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", @@ -2628,8 +2535,8 @@ } }, "node_modules/lightningcss": { - "version": "1.32.0", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "version": "1.33.0", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -2643,22 +2550,22 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "integrity": "sha1-8DOIURbf79nG9UeHUj41FLYeGWg=", + "version": "1.33.0", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", "cpu": [ "arm64" ], @@ -2677,8 +2584,8 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "version": "1.33.0", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", "cpu": [ "arm64" ], @@ -2697,8 +2604,8 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "integrity": "sha1-NfPpczLRMLnKGB4RtWje1q68bV4=", + "version": "1.33.0", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", "cpu": [ "x64" ], @@ -2717,8 +2624,8 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "integrity": "sha1-l3enZHK2Ttb/lDQq1kx7r9eUpXU=", + "version": "1.33.0", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", "cpu": [ "x64" ], @@ -2737,8 +2644,8 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "integrity": "sha1-E65lLhq3O5E117faFy9mbEEK1T0=", + "version": "1.33.0", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", "cpu": [ "arm" ], @@ -2757,12 +2664,15 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "integrity": "sha1-QXhYeVqUWS9oASOhsfnaig4e8zU=", + "version": "1.33.0", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2777,12 +2687,15 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "integrity": "sha1-a+NmkugQtxgECAL9gJYjz/5zITM=", + "version": "1.33.0", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2797,12 +2710,15 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "integrity": "sha1-C3gDr06yHP043Tn+Kru1PH3QkfY=", + "version": "1.33.0", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2817,12 +2733,15 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "integrity": "sha1-iNyLqGXd3bGsXvBLDxYYBEGMFjs=", + "version": "1.33.0", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2837,8 +2756,8 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "integrity": "sha1-TzC6P6XpJfW3n5RejMDRdsOxqzg=", + "version": "1.33.0", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", "cpu": [ "arm64" ], @@ -2857,8 +2776,8 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "integrity": "sha1-FBqlYFZFBkkokCu0rwRfp9n0Igo=", + "version": "1.33.0", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ "x64" ], @@ -2946,8 +2865,8 @@ } }, "node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.8", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.12", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2994,8 +2913,8 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.17", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.20", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "dev": true, "funding": [ { @@ -3017,26 +2936,6 @@ "dev": true, "license": "MIT" }, - "node_modules/node-fetch": { - "version": "2.7.0", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/obug": { "version": "2.1.1", "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", @@ -3100,12 +2999,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/pako": { - "version": "1.0.11", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", @@ -3165,8 +3058,8 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.7", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -3176,18 +3069,9 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/postcss": { - "version": "8.5.25", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.29", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "dev": true, "funding": [ { @@ -3205,9 +3089,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -3237,15 +3121,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/process": { - "version": "0.11.10", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/punycode": { "version": "2.3.1", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", @@ -3255,44 +3130,6 @@ "node": ">=6" } }, - "node_modules/quicktype-core": { - "version": "23.2.6", - "integrity": "sha512-asfeSv7BKBNVb9WiYhFRBvBZHcRutPRBwJMxW0pefluK4kkKu4lv0IvZBwFKvw2XygLcL1Rl90zxWDHYgkwCmA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@glideapps/ts-necessities": "2.2.3", - "browser-or-node": "^3.0.0", - "collection-utils": "^1.0.1", - "cross-fetch": "^4.0.0", - "is-url": "^1.2.4", - "js-base64": "^3.7.7", - "lodash": "^4.17.21", - "pako": "^1.0.6", - "pluralize": "^8.0.0", - "readable-stream": "4.5.2", - "unicode-properties": "^1.4.1", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^2.4.1" - } - }, - "node_modules/readable-stream": { - "version": "4.5.2", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", @@ -3322,12 +3159,12 @@ } }, "node_modules/rolldown": { - "version": "1.0.3", - "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "version": "1.2.13", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.153.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -3337,42 +3174,22 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" + } }, "node_modules/semver": { "version": "7.7.3", @@ -3414,8 +3231,8 @@ "license": "ISC" }, "node_modules/source-map-js": { - "version": "1.2.1", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -3434,15 +3251,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string_decoder": { - "version": "1.3.0", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", @@ -3483,12 +3291,6 @@ "node": ">=18" } }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", - "dev": true, - "license": "MIT" - }, "node_modules/tinybench": { "version": "2.9.0", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", @@ -3521,20 +3323,14 @@ } }, "node_modules/tinyrainbow": { - "version": "3.1.0", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "version": "3.2.0", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, "node_modules/ts-api-utils": { "version": "2.4.0", "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", @@ -3547,13 +3343,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/tslib": { - "version": "2.8.1", - "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", - "dev": true, - "license": "0BSD", - "optional": true - }, "node_modules/tsx": { "version": "4.22.4", "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", @@ -3603,32 +3392,6 @@ "dev": true, "license": "MIT" }, - "node_modules/unicode-properties": { - "version": "1.4.1", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/unicode-trie/node_modules/pako": { - "version": "0.2.9", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "dev": true, - "license": "MIT" - }, "node_modules/uri-js": { "version": "4.4.1", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", @@ -3638,22 +3401,16 @@ "punycode": "^2.1.0" } }, - "node_modules/urijs": { - "version": "1.19.11", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "dev": true, - "license": "MIT" - }, "node_modules/vite": { - "version": "8.0.16", - "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "version": "8.3.4", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.3", + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "bin": { @@ -3670,7 +3427,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -3722,18 +3479,18 @@ } }, "node_modules/vitest": { - "version": "4.1.8", - "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "version": "4.1.11", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -3761,12 +3518,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -3818,22 +3575,6 @@ "node": ">=14.0.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", @@ -3874,12 +3615,6 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, "node_modules/ws": { "version": "8.21.0", "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", @@ -3910,21 +3645,6 @@ "node": ">=18" } }, - "node_modules/yaml": { - "version": "2.9.0", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", diff --git a/nodejs/package.json b/nodejs/package.json index e6b1e9992c..d3b0dd5d52 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.92-4", + "copilotCliVersion": "1.0.97-2", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", @@ -80,16 +80,16 @@ "esbuild": "^0.28.1", "eslint": "^9.0.0", "glob": "^13.0.1", + "hpke-js": "^1.8.0", "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", "rimraf": "^6.1.2", "semver": "^7.7.3", "tar": "^7.5.22", "tsx": "^4.20.6", "typescript": "^5.0.0", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "ws": "^8.21.0" }, "engines": { diff --git a/nodejs/samples/package-lock.json b/nodejs/samples/package-lock.json index 3215d8b297..8b911dbef4 100644 --- a/nodejs/samples/package-lock.json +++ b/nodejs/samples/package-lock.json @@ -23,6 +23,7 @@ "zod": "4.3.6" }, "devDependencies": { + "@microsoft/agent-host-protocol-v09": "npm:@microsoft/agent-host-protocol@0.9.0", "@platformatic/vfs": "^0.3.0", "@types/node": "^25.2.0", "@types/semver": "7.8.0", @@ -32,16 +33,16 @@ "esbuild": "^0.28.1", "eslint": "^9.0.0", "glob": "^13.0.1", + "hpke-js": "^1.8.0", "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", "rimraf": "^6.1.2", "semver": "^7.7.3", "tar": "^7.5.22", "tsx": "^4.20.6", "typescript": "^5.0.0", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "ws": "^8.21.0" }, "engines": { @@ -222,31 +223,106 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "../node_modules/@glideapps/ts-necessities": { - "version": "2.2.3", + "../node_modules/@hpke/chacha20poly1305": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@hpke/chacha20poly1305/-/chacha20poly1305-1.8.0.tgz", + "integrity": "sha512-FcBfAQ+Y99vMNJP2yrZ9wpL8V0GOwp1+zMyzvc6alasrBygfFjFm1yeUtyADJCu/27C3Lm5mJzx6u7pwg+cX5w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/common": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@hpke/common/-/common-1.10.1.tgz", + "integrity": "sha512-moJwhmtLtuxiUzzNp1jpfBfx8yefKoO9D/RCR9dmwrnc7qjJqId1rEtQz+lSlU5cabX8daToMSx/7HayXOiaFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/core": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@hpke/core/-/core-1.9.0.tgz", + "integrity": "sha512-pFxWl1nNJeQCSUFs7+GAblHvXBCjn9EPN65vdKlYQil2aURaRxfGMO6vBKGqm1YHTKwiAxJQNEI70PbSowMP9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/dhkem-x25519": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@hpke/dhkem-x25519/-/dhkem-x25519-1.8.0.tgz", + "integrity": "sha512-S1MWWkAfu+TFxySgv5+2P3O4Mx/jk7BsoplzQaA1s3sfUJVJ2UsZsSzSsMc+FXJumLXncoJFlO6mK6mDGspfmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/dhkem-x448": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@hpke/dhkem-x448/-/dhkem-x448-1.8.0.tgz", + "integrity": "sha512-mFfnZfgp4OKkUIS/FKikfUgdnDKRy25ytCKBQiV+N+HbYy3I4v4ZCPBQ69QL+TYmKmCZJeUEnYeS5K+OBRP+Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } }, "../node_modules/@humanfs/core": { - "version": "0.19.1", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "../node_modules/@humanfs/node": { - "version": "0.16.7", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "../node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "../node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "dev": true, @@ -283,7 +359,9 @@ } }, "../node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -580,12 +658,22 @@ "url": "https://liberapay.com/Koromix" } }, + "../node_modules/@microsoft/agent-host-protocol-v09": { + "name": "@microsoft/agent-host-protocol", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@microsoft/agent-host-protocol/-/agent-host-protocol-0.9.0.tgz", + "integrity": "sha512-XY6zOqLSqlNianiWbEpZkzKRB2AKwcDPk9yAbp+afxyxhWzTfpJKy+03T5rIipJDnqf45rXiJ5JV/dzUA8JHLw==", + "dev": true, + "license": "MIT" + }, "../node_modules/@oxc-project/types": { - "version": "0.133.0", + "version": "0.153.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.153.0.tgz", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" } }, "../node_modules/@platformatic/vfs": { @@ -596,8 +684,44 @@ "node": ">= 22" } }, + "../node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.13.tgz", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.13.tgz", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "../node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.13.tgz", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", "cpu": [ "arm64" ], @@ -611,18 +735,246 @@ "node": "^20.19.0 || >=22.12.0" } }, + "../node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.13.tgz", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.13.tgz", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.13.tgz", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.13.tgz", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.13.tgz", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.13.tgz", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.13.tgz", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.13.tgz", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.13.tgz", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.13.tgz", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.13.tgz", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.13.tgz", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "../node_modules/@rolldown/pluginutils": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, "../node_modules/@standard-schema/spec": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, "license": "MIT" }, "../node_modules/@types/chai": { "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { @@ -632,6 +984,8 @@ }, "../node_modules/@types/deep-eql": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, @@ -658,6 +1012,13 @@ "undici-types": "~7.18.0" } }, + "../node_modules/@types/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", + "dev": true, + "license": "MIT" + }, "../node_modules/@types/ws": { "version": "8.18.1", "dev": true, @@ -878,14 +1239,16 @@ } }, "../node_modules/@vitest/expect": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -894,11 +1257,13 @@ } }, "../node_modules/@vitest/mocker": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -919,7 +1284,9 @@ } }, "../node_modules/@vitest/pretty-format": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -930,11 +1297,13 @@ } }, "../node_modules/@vitest/runner": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -942,12 +1311,14 @@ } }, "../node_modules/@vitest/snapshot": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -956,7 +1327,9 @@ } }, "../node_modules/@vitest/spy": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -964,11 +1337,13 @@ } }, "../node_modules/@vitest/utils": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -976,17 +1351,6 @@ "url": "https://opencollective.com/vitest" } }, - "../node_modules/abort-controller": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "../node_modules/acorn": { "version": "8.15.0", "dev": true, @@ -1028,6 +1392,8 @@ }, "../node_modules/assertion-error": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { @@ -1039,27 +1405,10 @@ "dev": true, "license": "MIT" }, - "../node_modules/base64-js": { - "version": "1.5.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "../node_modules/brace-expansion": { - "version": "1.1.16", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -1067,34 +1416,6 @@ "concat-map": "0.0.1" } }, - "../node_modules/browser-or-node": { - "version": "3.0.0", - "dev": true, - "license": "MIT" - }, - "../node_modules/buffer": { - "version": "6.0.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "../node_modules/callsites": { "version": "3.1.0", "dev": true, @@ -1104,7 +1425,9 @@ } }, "../node_modules/chai": { - "version": "6.2.2", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "dev": true, "license": "MIT", "engines": { @@ -1148,11 +1471,6 @@ "node": ">=18" } }, - "../node_modules/collection-utils": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0" - }, "../node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -1176,17 +1494,11 @@ }, "../node_modules/convert-source-map": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, - "../node_modules/cross-fetch": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, "../node_modules/cross-spawn": { "version": "7.0.6", "dev": true, @@ -1223,6 +1535,8 @@ }, "../node_modules/detect-libc": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1458,6 +1772,8 @@ }, "../node_modules/estree-walker": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { @@ -1472,22 +1788,6 @@ "node": ">=0.10.0" } }, - "../node_modules/event-target-shim": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../node_modules/events": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "../node_modules/expect-type": { "version": "1.3.0", "dev": true, @@ -1628,24 +1928,22 @@ "node": ">=8" } }, - "../node_modules/ieee754": { - "version": "1.2.1", + "../node_modules/hpke-js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/hpke-js/-/hpke-js-1.8.0.tgz", + "integrity": "sha512-N0PFQlUQsIPS9++nUNn2ZsxTPSv8pONyyrXIGZl0iiherRfS0XW1SvTd+RmepD0TN1S9zzTJkEutMIWWYt0/4w==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "@hpke/chacha20poly1305": "^1.8.0", + "@hpke/common": "^1.10.0", + "@hpke/core": "^1.9.0", + "@hpke/dhkem-x25519": "^1.8.0", + "@hpke/dhkem-x448": "^1.8.0" + }, + "engines": { + "node": ">=16.0.0" + } }, "../node_modules/ignore": { "version": "7.0.5", @@ -1697,21 +1995,11 @@ "node": ">=0.10.0" } }, - "../node_modules/is-url": { - "version": "1.2.4", - "dev": true, - "license": "MIT" - }, "../node_modules/isexe": { "version": "2.0.0", "dev": true, "license": "ISC" }, - "../node_modules/js-base64": { - "version": "3.7.8", - "dev": true, - "license": "BSD-3-Clause" - }, "../node_modules/js-yaml": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", @@ -1764,107 +2052,333 @@ "json2ts": "dist/src/cli.js" }, "engines": { - "node": ">=16.0.0" + "node": ">=16.0.0" + } + }, + "../node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "../node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "../node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "../node_modules/koffi": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-3.2.1.tgz", + "integrity": "sha512-0qE3lZ8jllRqPN4Ob6Ajl7c2bJSJDhQWuKLGP5hIEpHLllJWv1ydHFMhHmHc5p/W9GticKVDbYzZd7TBoQ4CZg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "url": "https://liberapay.com/Koromix" + }, + "optionalDependencies": { + "@koromix/koffi-android-arm64": "3.2.1", + "@koromix/koffi-android-x64": "3.2.1", + "@koromix/koffi-darwin-arm64": "3.2.1", + "@koromix/koffi-darwin-x64": "3.2.1", + "@koromix/koffi-freebsd-arm64": "3.2.1", + "@koromix/koffi-freebsd-ia32": "3.2.1", + "@koromix/koffi-freebsd-x64": "3.2.1", + "@koromix/koffi-linux-arm": "3.2.1", + "@koromix/koffi-linux-arm64": "3.2.1", + "@koromix/koffi-linux-ia32": "3.2.1", + "@koromix/koffi-linux-loong64": "3.2.1", + "@koromix/koffi-linux-riscv64": "3.2.1", + "@koromix/koffi-linux-x64": "3.2.1", + "@koromix/koffi-openbsd-ia32": "3.2.1", + "@koromix/koffi-openbsd-x64": "3.2.1", + "@koromix/koffi-win32-arm64": "3.2.1", + "@koromix/koffi-win32-ia32": "3.2.1", + "@koromix/koffi-win32-x64": "3.2.1" + } + }, + "../node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "../node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "../node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "../node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "../node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/json-schema-traverse": { - "version": "0.4.1", + "../node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "../node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", + "../node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "../node_modules/keyv": { - "version": "4.5.4", + "../node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/koffi": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/koffi/-/koffi-3.2.1.tgz", - "integrity": "sha512-0qE3lZ8jllRqPN4Ob6Ajl7c2bJSJDhQWuKLGP5hIEpHLllJWv1ydHFMhHmHc5p/W9GticKVDbYzZd7TBoQ4CZg==", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "url": "https://liberapay.com/Koromix" + "../node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, - "optionalDependencies": { - "@koromix/koffi-android-arm64": "3.2.1", - "@koromix/koffi-android-x64": "3.2.1", - "@koromix/koffi-darwin-arm64": "3.2.1", - "@koromix/koffi-darwin-x64": "3.2.1", - "@koromix/koffi-freebsd-arm64": "3.2.1", - "@koromix/koffi-freebsd-ia32": "3.2.1", - "@koromix/koffi-freebsd-x64": "3.2.1", - "@koromix/koffi-linux-arm": "3.2.1", - "@koromix/koffi-linux-arm64": "3.2.1", - "@koromix/koffi-linux-ia32": "3.2.1", - "@koromix/koffi-linux-loong64": "3.2.1", - "@koromix/koffi-linux-riscv64": "3.2.1", - "@koromix/koffi-linux-x64": "3.2.1", - "@koromix/koffi-openbsd-ia32": "3.2.1", - "@koromix/koffi-openbsd-x64": "3.2.1", - "@koromix/koffi-win32-arm64": "3.2.1", - "@koromix/koffi-win32-ia32": "3.2.1", - "@koromix/koffi-win32-x64": "3.2.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/levn": { - "version": "0.4.1", + "../node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/lightningcss": { - "version": "1.32.0", + "../node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">= 12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" } }, - "../node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", + "../node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "win32" ], "engines": { "node": ">= 12.0.0" @@ -1908,6 +2422,8 @@ }, "../node_modules/magic-string": { "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1937,7 +2453,9 @@ } }, "../node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.8", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1980,7 +2498,9 @@ "license": "MIT" }, "../node_modules/nanoid": { - "version": "3.3.17", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "dev": true, "funding": [ { @@ -2001,25 +2521,6 @@ "dev": true, "license": "MIT" }, - "../node_modules/node-fetch": { - "version": "2.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "../node_modules/obug": { "version": "2.1.1", "dev": true, @@ -2078,11 +2579,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "../node_modules/pako": { - "version": "1.0.11", - "dev": true, - "license": "(MIT AND Zlib)" - }, "../node_modules/parent-module": { "version": "1.0.1", "dev": true, @@ -2127,16 +2623,22 @@ }, "../node_modules/pathe": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "../node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "../node_modules/picomatch": { - "version": "4.0.4", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -2146,16 +2648,10 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "../node_modules/pluralize": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "../node_modules/postcss": { - "version": "8.5.25", + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "dev": true, "funding": [ { @@ -2173,9 +2669,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -2203,14 +2699,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "../node_modules/process": { - "version": "0.11.10", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "../node_modules/punycode": { "version": "2.3.1", "dev": true, @@ -2219,42 +2707,6 @@ "node": ">=6" } }, - "../node_modules/quicktype-core": { - "version": "23.2.6", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@glideapps/ts-necessities": "2.2.3", - "browser-or-node": "^3.0.0", - "collection-utils": "^1.0.1", - "cross-fetch": "^4.0.0", - "is-url": "^1.2.4", - "js-base64": "^3.7.7", - "lodash": "^4.17.21", - "pako": "^1.0.6", - "pluralize": "^8.0.0", - "readable-stream": "4.5.2", - "unicode-properties": "^1.4.1", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^2.4.1" - } - }, - "../node_modules/readable-stream": { - "version": "4.5.2", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "../node_modules/resolve-from": { "version": "4.0.0", "dev": true, @@ -2282,11 +2734,13 @@ } }, "../node_modules/rolldown": { - "version": "1.0.3", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.13.tgz", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.153.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -2296,41 +2750,22 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" - } - }, - "../node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" + } }, "../node_modules/semver": { "version": "7.7.3", @@ -2368,7 +2803,9 @@ "license": "ISC" }, "../node_modules/source-map-js": { - "version": "1.2.1", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -2385,14 +2822,6 @@ "dev": true, "license": "MIT" }, - "../node_modules/string_decoder": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "../node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -2430,11 +2859,6 @@ "node": ">=18" } }, - "../node_modules/tiny-inflate": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, "../node_modules/tinybench": { "version": "2.9.0", "dev": true, @@ -2464,18 +2888,15 @@ } }, "../node_modules/tinyrainbow": { - "version": "3.1.0", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "../node_modules/tr46": { - "version": "0.0.3", - "dev": true, - "license": "MIT" - }, "../node_modules/ts-api-utils": { "version": "2.4.0", "dev": true, @@ -2532,29 +2953,6 @@ "dev": true, "license": "MIT" }, - "../node_modules/unicode-properties": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "../node_modules/unicode-trie": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "../node_modules/unicode-trie/node_modules/pako": { - "version": "0.2.9", - "dev": true, - "license": "MIT" - }, "../node_modules/uri-js": { "version": "4.4.1", "dev": true, @@ -2563,20 +2961,17 @@ "punycode": "^2.1.0" } }, - "../node_modules/urijs": { - "version": "1.19.11", - "dev": true, - "license": "MIT" - }, "../node_modules/vite": { - "version": "8.0.16", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.3", + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "bin": { @@ -2593,7 +2988,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -2645,17 +3040,19 @@ } }, "../node_modules/vitest": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -2683,12 +3080,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -2739,20 +3136,6 @@ "node": ">=14.0.0" } }, - "../node_modules/webidl-conversions": { - "version": "3.0.1", - "dev": true, - "license": "BSD-2-Clause" - }, - "../node_modules/whatwg-url": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "../node_modules/which": { "version": "2.0.2", "dev": true, @@ -2790,11 +3173,6 @@ "node": ">=0.10.0" } }, - "../node_modules/wordwrap": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "../node_modules/ws": { "version": "8.21.0", "dev": true, @@ -2823,20 +3201,6 @@ "node": ">=18" } }, - "../node_modules/yaml": { - "version": "2.9.0", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "../node_modules/yocto-queue": { "version": "0.1.0", "dev": true, diff --git a/nodejs/scripts/package-release.ts b/nodejs/scripts/package-release.ts index 90ad30615c..7cd973a833 100644 --- a/nodejs/scripts/package-release.ts +++ b/nodejs/scripts/package-release.ts @@ -22,6 +22,7 @@ import { export const JAVA_CLASSIFIERS = { "linux-arm64": "linux.arm64", "linuxmusl-x64": "linuxmusl.x64", + "linuxmusl-arm64": "linuxmusl.arm64", "win32-x64": "win32", "win32-arm64": "win32.arm64", "darwin-arm64": "darwin", diff --git a/nodejs/scripts/publish-release.ts b/nodejs/scripts/publish-release.ts index 292926d409..4a164d7e92 100644 --- a/nodejs/scripts/publish-release.ts +++ b/nodejs/scripts/publish-release.ts @@ -24,6 +24,13 @@ type NativeCommand = ( env?: NodeJS.ProcessEnv ) => string; +type GithubRelease = { + tag_name: string; + draft: boolean; + prerelease: boolean; + published_at: string | null; +}; + const runNativeCommand: NativeCommand = (command, args, cwd, env = process.env) => execFileSync(command, args, { cwd, @@ -232,12 +239,7 @@ export async function publishJava( } export function previousSdkReleaseTag( - releases: { - tag_name: string; - draft: boolean; - prerelease: boolean; - published_at: string | null; - }[], + releases: GithubRelease[], identity: ReleaseIdentity ): string | undefined { return releases @@ -321,9 +323,24 @@ export async function publishSourceRelease( assert.equal(release.draft, false, "Existing SDK release is a draft"); return; } - const releases = JSON.parse( - gh(["api", "--paginate", "--slurp", `repos/${repository}/releases?per_page=100`]) - ).flat(); + let releases: GithubRelease[]; + if (identity.channel === "latest") { + try { + releases = [JSON.parse(gh(["api", `repos/${repository}/releases/latest`]))]; + } catch (error) { + if (!/\(HTTP 404\)/.test(String((error as { stderr?: string }).stderr))) throw error; + releases = []; + } + } else { + const output = gh([ + "api", + "--paginate", + "--jq", + ".[] | {tag_name, draft, prerelease, published_at}", + `repos/${repository}/releases?per_page=100`, + ]); + releases = output ? output.split("\n").map((line) => JSON.parse(line)) : []; + } const previous = previousSdkReleaseTag(releases, identity); gh([ "release", diff --git a/nodejs/scripts/unified-release.ts b/nodejs/scripts/unified-release.ts index 56b1b2ddae..5e1477ceb5 100644 --- a/nodejs/scripts/unified-release.ts +++ b/nodejs/scripts/unified-release.ts @@ -91,13 +91,12 @@ export function publicationSdks( destination !== "public" || visibility === "public", "Internal releases cannot publish publicly" ); - // Python publishes in the caller so PyPI authentication and attestations share one workflow identity. - return packagedSdks(channel, visibility).filter( - (language) => - language !== "python" && - (destination === "public" || - language === "nodejs" || - (channel !== "unstable" && language === "dotnet")) + // Public Python publishes in the caller so PyPI authentication and attestations share one workflow identity. + return packagedSdks(channel, visibility).filter((language) => + destination === "public" + ? language !== "python" + : language === "nodejs" || + (channel !== "unstable" && (language === "dotnet" || language === "python")) ); } diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 93029c8524..58d20a7d2c 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.92-4"; +export const COPILOT_CLI_VERSION = "1.0.97-2"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 24f7f6ff2e..464a525427 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -1662,6 +1662,9 @@ export class CopilotClient { if (config.gitHubToken !== undefined && config.gitHubTokenProvider !== undefined) { throw new Error("gitHubToken and gitHubTokenProvider are mutually exclusive"); } + if (config.cloud != null && config.skillProvider) { + throw new Error("Skill providers are not supported for cloud sessions."); + } if (!this.connection) { await this.start(); } @@ -1745,12 +1748,17 @@ export class CopilotClient { if (config.hooks) { s.registerHooks(config.hooks); } + if (config.skillProvider) { + s.registerSkillProvider(config.skillProvider); + } if (transformCallbacks) { s.registerTransformCallbacks(transformCallbacks); } if (config.onEvent) { s.on(config.onEvent); } + // Session-FS setup can throw, so finish it before the session + // becomes routable; a failed open must not leave handlers behind. this.setupSessionFs(s, config); this.sessions.set(sessionId, s); return s; @@ -1782,6 +1790,7 @@ export class CopilotClient { model: config.model, allowedModels: config.allowedModels, sessionId: localSessionId, + name: config.name, clientName: config.clientName, reasoningEffort: config.reasoningEffort, reasoningSummary: config.reasoningSummary, @@ -1798,6 +1807,7 @@ export class CopilotClient { isTerminal: tool.isTerminal, })), toolSearch: config.toolSearch, + imageGeneration: config.imageGeneration, canvases: config.canvases?.map((canvas) => canvas.declaration), requestCanvasRenderer: config.requestCanvasRenderer, requestExtensions: config.requestExtensions, @@ -1862,6 +1872,9 @@ export class CopilotClient { enableSessionStore: config.enableSessionStore, enableSkills: config.enableSkills, skillDirectories: config.skillDirectories, + ...(config.skillProvider ? { hasSkillProvider: true } : {}), + agentDirectories: config.agentDirectories, + hookDirectories: config.hookDirectories, pluginDirectories: config.pluginDirectories, instructionDirectories: config.instructionDirectories, disabledSkills: config.disabledSkills, @@ -1875,6 +1888,7 @@ export class CopilotClient { featureFlags: config.featureFlags, expAssignments: config.expAssignments, enableManagedSettings: config.enableManagedSettings, + enforceManagedModelDefaults: config.enforceManagedModelDefaults, managedSettings: config.managedSettings, }); @@ -2041,6 +2055,9 @@ export class CopilotClient { if (config.hooks) { session.registerHooks(config.hooks); } + if (config.skillProvider) { + session.registerSkillProvider(config.skillProvider); + } const modeDefaults = this.configDefaultsForMode(); config = { ...modeDefaults, ...config }; @@ -2057,10 +2074,13 @@ export class CopilotClient { if (config.onEvent) { session.on(config.onEvent); } + // Validation and session-FS setup can throw, so finish them before the + // replacement session becomes routable over any resident one. + const toolFilterOptions = this.resolveToolFilterOptions(config); this.setupSessionFs(session, config); + const replacedSession = this.sessions.get(sessionId); this.sessions.set(sessionId, session); - const toolFilterOptions = this.resolveToolFilterOptions(config); const gitHubTokenProviderRegistrationId = this.registerGitHubTokenProvider( config.gitHubTokenProvider, sessionId @@ -2103,6 +2123,7 @@ export class CopilotClient { isTerminal: tool.isTerminal, })), toolSearch: config.toolSearch, + imageGeneration: config.imageGeneration, canvases: config.canvases?.map((canvas) => canvas.declaration), workflows: workflows?.map((workflow) => workflow.meta), requestCanvasRenderer: config.requestCanvasRenderer, @@ -2159,6 +2180,9 @@ export class CopilotClient { defaultAgent: config.defaultAgent, agent: config.agent, skillDirectories: config.skillDirectories, + ...(config.skillProvider ? { hasSkillProvider: true } : {}), + agentDirectories: config.agentDirectories, + hookDirectories: config.hookDirectories, pluginDirectories: config.pluginDirectories, instructionDirectories: config.instructionDirectories, disabledSkills: config.disabledSkills, @@ -2174,6 +2198,7 @@ export class CopilotClient { featureFlags: config.featureFlags, expAssignments: config.expAssignments, enableManagedSettings: config.enableManagedSettings, + enforceManagedModelDefaults: config.enforceManagedModelDefaults, managedSettings: config.managedSettings, ...(extensionOptions?.requestedEnvironmentVariables ? { @@ -2222,7 +2247,15 @@ export class CopilotClient { this.commitGitHubTokenProvider(sessionId, gitHubTokenProviderRegistrationId); } catch (e) { session._markDisconnected(); - this.sessions.delete(sessionId); + // The runtime keeps the resident session's bindings when a resume + // fails, so its callbacks must keep reaching the replaced session. + if (this.sessions.get(sessionId) === session) { + if (replacedSession) { + this.sessions.set(sessionId, replacedSession); + } else { + this.sessions.delete(sessionId); + } + } if (gitHubTokenProviderRegistrationId !== undefined) { this.githubTokenProviders.delete(gitHubTokenProviderRegistrationId); } @@ -2243,7 +2276,7 @@ export class CopilotClient { * This connection owns the host. Disposing it or disconnecting the client * stops the listener without deleting sessions. The host uses a separate * SDK connection to the same runtime, not another runtime process. - * Only one AHP host may own the catalog in an effective Copilot home + * Only one AHP host may own a compute-scoped catalog in an effective Copilot home * at a time. Other SDK clients and sessions remain usable in that home. * Select localServer, githubEnvironment, or both. An empty localServer * selects 127.0.0.1 on an available port. `onExit` runs at most once; owner disconnection cannot @@ -2261,6 +2294,7 @@ export class CopilotClient { const rpc = this.rpc; const hostId = randomUUID(); const { + computeId, localServer, githubEnvironment, onExit, @@ -2281,6 +2315,7 @@ export class CopilotClient { try { const info = await rpc.host.start({ hostId, + computeId, localServer, githubEnvironment, sessionFactory: createSession ? true : undefined, @@ -2291,7 +2326,8 @@ export class CopilotClient { async () => { await rpc.host.dispose({ hostId }); }, - (sessionId) => rpc.host.publishSession({ hostId, sessionId }) + (sessionId) => rpc.host.publishSession({ hostId, sessionId }), + () => rpc.host.listSessions({ hostId }) ); } catch (error) { this.hostExitCallbacks.delete(hostId); @@ -3224,6 +3260,8 @@ export class CopilotClient { /** Starts the in-process FFI runtime with SDK-managed typed options. */ private async startInProcessFfi(): Promise { const explicitEntrypoint = this.resolvedEnv.COPILOT_CLI_PATH; + const cliLoginSyncIntegrationId = + this.resolvedEnv.GITHUB_COPILOT_INTEGRATION_ID?.trim() || undefined; let runtimeLibrary: string; if (explicitEntrypoint) { const entrypointDirectory = dirname(resolve(explicitEntrypoint)); @@ -3237,7 +3275,8 @@ export class CopilotClient { "runtime.node" ); } else { - runtimeLibrary = join(dirname(await getBundledRuntimePath()), "runtime.node"); + const bundledRuntimePath = await getBundledRuntimePath(); + runtimeLibrary = join(dirname(bundledRuntimePath), "runtime.node"); } // Load the FFI host lazily so the native `koffi` addon (and its // platform-specific `koffi.node`) is only loaded on the in-process path; @@ -3272,6 +3311,9 @@ export class CopilotClient { if (this.options.enableRemoteSessions) { args.push("--remote"); } + if (cliLoginSyncIntegrationId) { + args.push(`--cli-login-sync-integration-id=${cliLoginSyncIntegrationId}`); + } const host = FfiRuntimeHost.create(runtimeLibrary, explicitEntrypoint, environment, args); this.ffiHost = host; @@ -3513,6 +3555,23 @@ export class CopilotClient { } ); + // Internal experimental callbacks backing `SessionConfigBase.skillProvider`. + this.connection.onRequest( + "skillProvider.list", + async (params: { sessionId: string }, token: CancellationToken) => + await this.resolveSkillProviderSession(params)._handleSkillProviderList(token) + ); + this.connection.onRequest( + "skillProvider.read", + async (params: { sessionId: string; name: string }, token: CancellationToken) => { + const session = this.resolveSkillProviderSession(params); + if (typeof params.name !== "string") { + throw new Error("Invalid skillProvider.read payload"); + } + return await session._handleSkillProviderRead(params.name, token); + } + ); + const connection = this.connection; const messageWriter = this.messageWriter; const cliProcess = this.isExternalServer ? null : this.cliProcess; @@ -3736,6 +3795,17 @@ export class CopilotClient { return { response }; } + private resolveSkillProviderSession(params: { sessionId: string }): CopilotSession { + if (!params || typeof params.sessionId !== "string") { + throw new Error("Invalid skillProvider payload"); + } + const session = this.sessions.get(params.sessionId); + if (!session) { + throw new Error(`Session not found: ${params.sessionId}`); + } + return session; + } + private async handleHooksInvoke(params: { sessionId: string; hookType: string; diff --git a/nodejs/src/extension.ts b/nodejs/src/extension.ts index e7bb21e3b2..f6adc32745 100644 --- a/nodejs/src/extension.ts +++ b/nodejs/src/extension.ts @@ -24,7 +24,7 @@ export { export type JoinSessionConfig = Omit< ResumeSessionConfig, - "onPermissionRequest" | "extensionSdkPath" + "onPermissionRequest" | "extensionSdkPath" | "skillProvider" | "imageGeneration" > & { onPermissionRequest?: PermissionHandler; /** @@ -124,16 +124,25 @@ export async function joinSession(config: JoinSessionConfig = {}): Promise